// CodeContracts
// 
// Copyright (c) Microsoft Corporation
// 
// All rights reserved. 
// 
// MIT License
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#if !NoWriter
using System;
using System.Collections;
#if CCINamespace
using Microsoft.Cci.Metadata;
#else
using System.Compiler.Metadata;
#endif
using System.Diagnostics;
using System.IO;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Security;
#if !ROTOR
using System.Security.Cryptography;
#endif
using System.Text;

#if CCINamespace
namespace Microsoft.Cci{
#else
namespace System.Compiler{
#endif
#if !ROTOR
  [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("B01FAFEB-C450-3A4D-BEEC-B4CEEC01E006"), SuppressUnmanagedCodeSecurity]
  interface ISymUnmanagedDocumentWriter{
    void SetSource(uint sourceSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] byte[] source);
    void SetCheckSum(ref Guid algorithmId, uint checkSumSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] byte[] checkSum);
  };
  [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("2DE91396-3844-3B1D-8E91-41C24FD672EA"), SuppressUnmanagedCodeSecurity]
  interface ISymUnmanagedWriter{
    ISymUnmanagedDocumentWriter DefineDocument(string url, ref Guid language, ref Guid languageVendor, ref Guid documentType); 
    void SetUserEntryPoint(uint entryMethod);
    void OpenMethod(uint method);
    void CloseMethod();
    uint OpenScope(uint startOffset); 
    void CloseScope(uint endOffset);
    void SetScopeRange(uint scopeID, uint startOffset, uint endOffset);
    void DefineLocalVariable(string name, uint attributes, uint cSig, IntPtr signature, uint addrKind, uint addr1, uint addr2, uint startOffset, uint endOffset);
    void DefineParameter(string name, uint attributes, uint sequence, uint addrKind, uint addr1, uint addr2, uint addr3);
    void DefineField(uint parent, string name, uint attributes, uint cSig, IntPtr signature, uint addrKind, uint addr1, uint addr2, uint addr3); 
    void DefineGlobalVariable(string name, uint attributes, uint cSig, IntPtr signature, uint addrKind, uint addr1, uint addr2, uint addr3); 
    void Close();
    void SetSymAttribute(uint parent, string name, uint cData, IntPtr signature);
    void OpenNamespace(string name);
    void CloseNamespace();
    void UsingNamespace(string fullName);
    void SetMethodSourceRange(ISymUnmanagedDocumentWriter startDoc, uint startLine, uint startColumn, object endDoc, uint endLine, uint endColumn);
    void Initialize([MarshalAs(UnmanagedType.IUnknown)]object emitter, string filename, [MarshalAs(UnmanagedType.IUnknown)]object pIStream, bool fFullBuild);
    void GetDebugInfo(ref ImageDebugDirectory pIDD, uint cData, out uint pcData, IntPtr data);
    void DefineSequencePoints(ISymUnmanagedDocumentWriter document, uint spCount, 
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] uint[] offsets,
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] uint[] lines, 
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] uint[] columns,
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] uint[] endLines, 
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] uint[] endColumns);
    void RemapToken(uint oldToken, uint newToken);
    void Initialize2([MarshalAs(UnmanagedType.IUnknown)]object emitter, string tempfilename, [MarshalAs(UnmanagedType.IUnknown)]object pIStream, bool fFullBuild, string finalfilename);
    void DefineConstant(string name, object value, uint cSig, IntPtr signature);
  }
  struct ImageDebugDirectory{
    internal int   Characteristics;
    internal int   TimeDateStamp;
    internal short MajorVersion;
    internal short MinorVersion;
    internal int   Type;
    internal int   SizeOfData;
    internal int   AddressOfRawData;
    internal int   PointerToRawData;
    public ImageDebugDirectory(bool zeroFill){
      this.Characteristics = 0;
      this.TimeDateStamp = 0;
      this.MajorVersion = 0;
      this.MinorVersion = 0;
      this.Type = 0;
      this.SizeOfData = 0;
      this.AddressOfRawData = 0;
      this.PointerToRawData = 0;
    }
  }

  [ComVisible(true), ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("BA3FEE4C-ECB9-4e41-83B7-183FA41CD859")]
  unsafe public interface IMetaDataEmit{
    void SetModuleProps(string szName); 
    void Save(string szFile, uint dwSaveFlags);
    void SaveToStream(void* pIStream, uint dwSaveFlags); 
    uint GetSaveSize(uint fSave); 
    uint DefineTypeDef(char* szTypeDef, uint dwTypeDefFlags, uint tkExtends, uint* rtkImplements);
    uint DefineNestedType(char* szTypeDef, uint dwTypeDefFlags, uint tkExtends, uint* rtkImplements, uint tdEncloser); 
    void SetHandler([MarshalAs(UnmanagedType.IUnknown), In]object pUnk); 
    uint DefineMethod(uint td, char* zName, uint dwMethodFlags, byte* pvSigBlob, uint cbSigBlob, uint ulCodeRVA, uint dwImplFlags);   
    void DefineMethodImpl(uint td, uint tkBody, uint tkDecl);
    uint DefineTypeRefByName(uint tkResolutionScope, char* szName);
    uint DefineImportType(IntPtr pAssemImport, void* pbHashValue, uint cbHashValue, IMetaDataImport pImport,
      uint tdImport, IntPtr pAssemEmit);
    uint DefineMemberRef(uint tkImport, string szName, byte* pvSigBlob, uint cbSigBlob);
    uint DefineImportMember(IntPtr pAssemImport, void* pbHashValue, uint cbHashValue, 
      IMetaDataImport pImport, uint mbMember, IntPtr pAssemEmit, uint tkParent);
    uint DefineEvent(uint td, string szEvent, uint dwEventFlags, uint tkEventType, uint mdAddOn, uint mdRemoveOn, uint mdFire, uint *rmdOtherMethods);
    void SetClassLayout(uint td, uint dwPackSize, COR_FIELD_OFFSET* rFieldOffsets, uint ulClassSize);
    void DeleteClassLayout(uint td);
    void SetFieldMarshal(uint tk, byte* pvNativeType, uint cbNativeType);
    void DeleteFieldMarshal(uint tk);
    uint DefinePermissionSet (uint tk, uint dwAction, void* pvPermission, uint cbPermission);
    void SetRVA(uint md, uint ulRVA);
    uint GetTokenFromSig(byte* pvSig, uint cbSig);
    uint DefineModuleRef(string szName);
    void SetParent(uint mr, uint tk);
    uint GetTokenFromTypeSpec(byte* pvSig, uint cbSig);
    void SaveToMemory(void* pbData, uint cbData);
    uint DefineUserString(string szString, uint cchString);
    void DeleteToken(uint tkObj);
    void SetMethodProps(uint md, uint dwMethodFlags, uint ulCodeRVA, uint dwImplFlags);
    void SetTypeDefProps(uint td, uint dwTypeDefFlags, uint tkExtends, uint* rtkImplements);
    void SetEventProps(uint ev, uint dwEventFlags, uint tkEventType, uint mdAddOn, uint mdRemoveOn, uint mdFire, uint* rmdOtherMethods);
    uint SetPermissionSetProps(uint tk, uint dwAction, void* pvPermission, uint cbPermission);
    void DefinePinvokeMap(uint tk, uint dwMappingFlags, string szImportName, uint mrImportDLL);
    void SetPinvokeMap(uint tk, uint dwMappingFlags, string szImportName, uint mrImportDLL);
    void DeletePinvokeMap(uint tk);
    uint DefineCustomAttribute(uint tkObj, uint tkType, void* pCustomAttribute, uint cbCustomAttribute);
    void SetCustomAttributeValue(uint pcv, void* pCustomAttribute, uint cbCustomAttribute);
    uint DefineField(uint td, string szName, uint dwFieldFlags, byte* pvSigBlob, uint cbSigBlob, uint dwCPlusTypeFlag, void* pValue, uint cchValue);
    uint DefineProperty(uint td, string szProperty, uint dwPropFlags, byte *pvSig, uint cbSig, uint dwCPlusTypeFlag, 
      void* pValue, uint cchValue, uint mdSetter, uint mdGetter, uint *rmdOtherMethods);
    uint DefineParam(uint md, uint ulParamSeq, string szName, uint dwParamFlags, uint dwCPlusTypeFlag, void* pValue, uint cchValue);
    void SetFieldProps(uint fd, uint dwFieldFlags, uint dwCPlusTypeFlag, void* pValue, uint cchValue);
    void SetPropertyProps(uint  pr, uint dwPropFlags, uint dwCPlusTypeFlag, void* pValue, uint cchValue, uint mdSetter, uint mdGetter, uint* rmdOtherMethods);
    void SetParamProps(uint pd, string szName, uint dwParamFlags, uint dwCPlusTypeFlag, void* pValue, uint cchValue);
    uint DefineSecurityAttributeSet(uint tkObj, IntPtr rSecAttrs, uint cSecAttrs);
    void ApplyEditAndContinue([MarshalAs(UnmanagedType.IUnknown)]object pImport);
    uint TranslateSigWithScope(IntPtr pAssemImport, void* pbHashValue, uint cbHashValue, 
      IMetaDataImport import, byte* pbSigBlob, uint cbSigBlob, IntPtr pAssemEmit, IMetaDataEmit emit, byte* pvTranslatedSig, uint cbTranslatedSigMax);
    void SetMethodImplFlags(uint md, uint dwImplFlags);
    void SetFieldRVA(uint  fd, uint ulRVA);
    void Merge(IMetaDataImport pImport, IntPtr pHostMapToken, [MarshalAs(UnmanagedType.IUnknown)]object  pHandler);
    void MergeEnd();
  }
  public struct COR_FIELD_OFFSET{
    public uint ridOfField; 
    public uint ulOffset;   
  }
  [ComVisible(true), ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("7DAC8207-D3AE-4c75-9B67-92801A497D44")]
  unsafe public interface IMetaDataImport{
    [PreserveSig]void CloseEnum(uint hEnum);
    uint CountEnum(uint hEnum);
    void ResetEnum(uint hEnum, uint ulPos);
    uint EnumTypeDefs(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rTypeDefs, uint cMax);
    uint EnumInterfaceImpls(ref uint phEnum, uint td, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] uint[] rImpls,  uint cMax);
    uint EnumTypeRefs(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rTypeRefs, uint cMax);
    uint FindTypeDefByName(string szTypeDef, uint tkEnclosingClass);
    Guid GetScopeProps(StringBuilder szName, uint cchName, out uint pchName);
    uint GetModuleFromScope();
    uint GetTypeDefProps(uint td, IntPtr szTypeDef, uint cchTypeDef, out uint pchTypeDef, IntPtr pdwTypeDefFlags);
    uint GetInterfaceImplProps(uint iiImpl, out uint pClass);       
    uint GetTypeRefProps(uint tr, out uint ptkResolutionScope, StringBuilder szName, uint cchName);        
    uint ResolveTypeRef(uint tr, [In] ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppIScope);
    uint EnumMembers(ref uint phEnum, uint cl, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] uint[] rMembers, uint cMax); 
    uint EnumMembersWithName(ref uint phEnum, uint cl, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rMembers, uint cMax);
    uint EnumMethods(ref uint phEnum, uint cl, uint* rMethods, uint cMax);    
    uint EnumMethodsWithName(ref uint phEnum, uint cl, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rMethods, uint cMax);    
    uint EnumFields(ref uint phEnum, uint cl, uint* rFields, uint cMax);   
    uint EnumFieldsWithName(ref uint phEnum, uint cl, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rFields, uint cMax);   
    uint EnumParams(ref uint phEnum, uint mb, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] uint[] rParams, uint cMax);   
    uint EnumMemberRefs(ref uint phEnum, uint tkParent, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] uint[] rMemberRefs, uint cMax);       
    uint EnumMethodImpls(ref uint phEnum, uint td, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rMethodBody, 
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rMethodDecl, uint cMax);
    uint EnumPermissionSets(ref uint phEnum, uint tk, uint dwActions, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rPermission, 
      uint cMax); 
    uint FindMember(uint td, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] byte[] pvSigBlob, uint cbSigBlob);   
    uint FindMethod(uint td, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] byte[] pvSigBlob, uint cbSigBlob);  
    uint FindField(uint td, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] byte[] pvSigBlob, uint cbSigBlob);    
    uint FindMemberRef(uint td, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] byte[] pvSigBlob, uint cbSigBlob);   
    uint GetMethodProps(uint mb, out uint pClass, IntPtr szMethod, uint cchMethod, out uint pchMethod, IntPtr pdwAttr, 
      IntPtr ppvSigBlob, IntPtr pcbSigBlob, IntPtr pulCodeRVA);   
    unsafe uint GetMemberRefProps(uint mr, ref uint ptk, StringBuilder szMember, uint cchMember, out uint pchMember, out byte* ppvSigBlob);   
    uint EnumProperties(ref uint phEnum, uint td, uint* rProperties, uint cMax);  
    uint EnumEvents(ref uint phEnum, uint td, uint* rEvents, uint cMax);   
    uint GetEventProps(uint ev, out uint pClass, StringBuilder szEvent, uint cchEvent, out uint pchEvent, out uint pdwEventFlags, 
      out uint ptkEventType, out uint pmdAddOn, out uint pmdRemoveOn, out uint pmdFire, 
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 11)] uint[] rmdOtherMethod, uint cMax);  
    uint EnumMethodSemantics(ref uint phEnum, uint mb, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] uint[] rEventProp, uint cMax);  
    uint GetMethodSemantics(uint mb, uint tkEventProp);   
    uint GetClassLayout(uint td, out uint pdwPackSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] COR_FIELD_OFFSET[] rFieldOffset, uint cMax, out uint pcFieldOffset); 
    unsafe uint GetFieldMarshal( uint tk, out byte* ppvNativeType); 
    uint GetRVA(uint tk, out uint pulCodeRVA);  
    unsafe uint GetPermissionSetProps(uint pm, out uint pdwAction, out void* ppvPermission);  
    unsafe uint GetSigFromToken(uint mdSig, out byte *ppvSig);  
    uint GetModuleRefProps(uint mur, StringBuilder szName, uint cchName); 
    uint EnumModuleRefs(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rModuleRefs, uint cmax);  
    unsafe uint GetTypeSpecFromToken(uint typespec, out byte * ppvSig); 
    uint GetNameFromToken(uint tk); 
    uint EnumUnresolvedMethods(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rMethods, uint cMax);   
    uint GetUserString(uint stk, StringBuilder szString, uint cchString); 
    uint GetPinvokeMap(uint tk, out uint pdwMappingFlags, StringBuilder   szImportName, uint cchImportName, out uint pchImportName);
    uint EnumSignatures(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rSignatures, uint cmax); 
    uint EnumTypeSpecs(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rTypeSpecs, uint cmax);   
    uint EnumUserStrings(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rStrings, uint cmax); 
    [PreserveSig]
    int GetParamForMethodIndex(uint md, uint ulParamSeq, out uint pParam); 
    uint EnumCustomAttributes(ref uint phEnum, uint tk, uint tkType, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=4)] uint[] rCustomAttributes, uint cMax);
    uint GetCustomAttributeProps(uint cv, out uint ptkObj, out uint ptkType, out void * ppBlob);
    uint FindTypeRef(uint tkResolutionScope, string szName); 
    uint GetMemberProps(uint mb, out uint pClass, StringBuilder szMember, uint cchMember, out uint pchMember, out uint pdwAttr, 
      out byte* ppvSigBlob, out uint pcbSigBlob, out uint pulCodeRVA, out uint pdwImplFlags, out uint pdwCPlusTypeFlag, out void* ppValue);
    uint GetFieldProps(uint mb, out uint pClass, StringBuilder szField, uint cchField, out uint pchField, out uint pdwAttr, 
      out byte* ppvSigBlob,  out uint pcbSigBlob, out uint pdwCPlusTypeFlag, out void* ppValue); 
    uint GetPropertyProps(uint prop, out uint pClass, StringBuilder szProperty, uint cchProperty, out uint pchProperty, out uint pdwPropFlags, 
      out byte* ppvSig, out uint pbSig, out uint pdwCPlusTypeFlag, out void* ppDefaultValue, out uint pcchDefaultValue, out uint pmdSetter, 
      out uint pmdGetter, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 14)] uint[] rmdOtherMethod, uint cMax); 
    uint GetParamProps(uint tk, out uint pmd, out uint pulSequence, StringBuilder szName, uint cchName, out uint pchName, 
      out uint pdwAttr, out uint pdwCPlusTypeFlag, out void* ppValue);
    uint GetCustomAttributeByName(uint tkObj, string szName, out void*  ppData); 
    [PreserveSig][return: MarshalAs(UnmanagedType.Bool)]
    bool IsValidToken( uint tk); 
    uint GetNestedClassProps(uint tdNestedClass);
    uint GetNativeCallConvFromSig(void* pvSig, uint cbSig); 
    int IsGlobal(uint pd);
  }
  [SuppressUnmanagedCodeSecurity]
  internal sealed class Ir2md : IMetaDataEmit, IMetaDataImport{
#else
  internal sealed class Ir2md{
#endif
    private AssemblyNode assembly;
    private Module/*!*/ module;
    private MetadataWriter/*!*/ writer;
    private bool UseGenerics = false;
    private bool StripOptionalModifiersFromLocals {
        get { return this.module.StripOptionalModifiersFromLocals; }
    }
    private BinaryWriter/*!*/ blobHeap = new BinaryWriter(new MemoryStream(), System.Text.Encoding.Unicode);
#if WHIDBEYwithGenerics || WHIDBEYwithGenericsAndIEqualityComparer
    private Hashtable/*!*/ blobHeapIndex = new Hashtable(new ByteArrayKeyComparer());
#else
    private Hashtable/*!*/ blobHeapIndex = new Hashtable(new ByteArrayHasher(), new ByteArrayComparer());
#endif
    private Hashtable/*!*/ blobHeapStringIndex = new Hashtable();
    private NodeList/*!*/ nodesWithCustomAttributes = new NodeList();
    private int customAttributeCount = 0;
    private NodeList/*!*/ nodesWithSecurityAttributes = new NodeList();
    private int securityAttributeCount = 0;
    private NodeList/*!*/ constantTableEntries = new NodeList();
    private TrivialHashtable/*!*/ assemblyRefIndex = new TrivialHashtable();
    private AssemblyReferenceList/*!*/ assemblyRefEntries = new AssemblyReferenceList();
    private TypeNodeList/*!*/ classLayoutEntries = new TypeNodeList();
    private TrivialHashtable/*!*/ documentMap = new TrivialHashtable();
    private TrivialHashtable/*!*/ eventIndex = new TrivialHashtable();
    private EventList/*!*/ eventEntries = new EventList();
    private TrivialHashtable/*!*/ eventMapIndex = new TrivialHashtable();
    private EventList/*!*/ eventMapEntries = new EventList();
    private TrivialHashtable/*!*/ exceptionBlock = new TrivialHashtable();
    private TrivialHashtable/*!*/ fieldIndex = new TrivialHashtable();
    private FieldList/*!*/ fieldEntries = new FieldList();
    private FieldList/*!*/ fieldLayoutEntries = new FieldList();
    private FieldList/*!*/ fieldRvaEntries = new FieldList();
    private Hashtable/*!*/ fileTableIndex = new Hashtable();
    private ModuleList/*!*/ fileTableEntries = new ModuleList();
    private Hashtable/*!*/ genericParamIndex = new Hashtable();
    private MemberList/*!*/ genericParamEntries = new MemberList();
    private TypeNodeList/*!*/ genericParameters = new TypeNodeList();
    private TypeNodeList/*!*/ genericParamConstraintEntries = new TypeNodeList();
    private ArrayList/*!*/ guidEntries = new ArrayList();
    private Hashtable/*!*/ guidIndex = new Hashtable();
    private MethodList/*!*/ implMapEntries = new MethodList();
    private TypeNodeList/*!*/ interfaceEntries = new TypeNodeList();
    private NodeList/*!*/ marshalEntries = new NodeList();
    private TrivialHashtable<int>/*!*/ memberRefIndex = new TrivialHashtable<int>();
    private MemberList/*!*/ memberRefEntries = new MemberList();
    private TrivialHashtable/*!*/ methodBodiesHeapIndex = new TrivialHashtable();
    private BinaryWriter/*!*/ methodBodiesHeap = new BinaryWriter(new MemoryStream());
    private BinaryWriter/*!*/ methodBodyHeap;
    private MethodList/*!*/ methodEntries = new MethodList();
    private TrivialHashtable<int>/*!*/ methodIndex = new TrivialHashtable<int>();
    private MethodList/*!*/ methodImplEntries = new MethodList();
    private MethodInfo/*!*/ methodInfo;
#if !MinimalReader && !CodeContracts
    private Method currentMethod;
#endif
    private MemberList/*!*/ methodSemanticsEntries = new MemberList();
    private MethodList/*!*/ methodSpecEntries = new MethodList();
    private Hashtable/*!*/ methodSpecIndex = new Hashtable();
    private ModuleReferenceList/*!*/ moduleRefEntries = new ModuleReferenceList();
    private Hashtable/*!*/ moduleRefIndex = new Hashtable();
    private TypeNodeList/*!*/ nestedClassEntries = new TypeNodeList();
    private TrivialHashtable<int>/*!*/ paramIndex = new TrivialHashtable<int>();
    private ParameterList/*!*/ paramEntries = new ParameterList();
    private TrivialHashtable/*!*/ propertyIndex = new TrivialHashtable();
    private PropertyList/*!*/ propertyEntries = new PropertyList();
    private TrivialHashtable/*!*/ propertyMapIndex = new TrivialHashtable();
    private PropertyList/*!*/ propertyMapEntries = new PropertyList();
    private BinaryWriter/*!*/ resourceDataHeap = new BinaryWriter(new MemoryStream());
    private BinaryWriter/*!*/ sdataHeap = new BinaryWriter(new MemoryStream());
#if !ROTOR
    private ISymUnmanagedWriter symWriter = null;
#endif
    private int stackHeight;
    private int stackHeightMax;
    private int stackHeightExitTotal;
    private ArrayList/*!*/ standAloneSignatureEntries = new ArrayList();
    private BinaryWriter/*!*/ stringHeap = new BinaryWriter(new MemoryStream());
    private Hashtable/*!*/ stringHeapIndex = new Hashtable();
    private BinaryWriter/*!*/ tlsHeap = new BinaryWriter(new MemoryStream());
    private TrivialHashtable/*!*/ typeDefIndex = new TrivialHashtable();
    private TypeNodeList/*!*/ typeDefEntries = new TypeNodeList();
    private TrivialHashtable/*!*/ typeRefIndex = new TrivialHashtable();
    private TypeNodeList/*!*/ typeRefEntries = new TypeNodeList();
    private TrivialHashtable/*!*/ typeSpecIndex = new TrivialHashtable();
    private TrivialHashtable/*!*/ structuralTypeSpecIndexFor = new TrivialHashtable();
    private TypeNodeList/*!*/ typeSpecEntries = new TypeNodeList();
    private TrivialHashtable/*!*/ typeParameterNumber = new TrivialHashtable();
    private BinaryWriter/*!*/ userStringHeap = new BinaryWriter(new MemoryStream(), System.Text.Encoding.Unicode);
    private Hashtable/*!*/ userStringHeapIndex = new Hashtable();
    private byte[] PublicKey;
    private int SignatureKeyLength;

    internal Ir2md(Module/*!*/ module) {
      this.assembly = module as AssemblyNode;
      this.module = module;
      //^ base();
      this.blobHeap.Write((byte)0);
      this.stringHeap.Write((byte)0);
      this.userStringHeap.Write((byte)0);
      if (this.assembly != null) {
        this.PublicKey = this.assembly.PublicKeyOrToken;
        this.SignatureKeyLength = 0;
        for (int j = 0; j < this.assembly.Attributes.Count; j++) {
          AttributeNode node = this.assembly.Attributes[j];
          if (node == null) continue;
          if (node.Type.ToString() == "System.Reflection.AssemblySignatureKeyAttribute") {
            string rawString = node.GetPositionalArgument(0).ToString();
            this.SignatureKeyLength = rawString.Length / 2;
          }
        }
      }
    }
    internal static void WritePE(Module/*!*/ module, string debugSymbolsLocation, BinaryWriter/*!*/ writer) {
      Ir2md ir2md = new Ir2md(module);
      try{
        ir2md.SetupMetadataWriter(debugSymbolsLocation);
        MetadataWriter mdWriter = ir2md.writer;
        mdWriter.WritePE(writer);
      }finally{
#if !ROTOR
        if (ir2md.symWriter != null) 
          ir2md.symWriter.Close();
#endif
        ir2md.assembly = null;
        ir2md.assemblyRefEntries = null;
        ir2md.assemblyRefIndex = null;
        ir2md.blobHeap = null;
        ir2md.blobHeapIndex = null;
        ir2md.blobHeapStringIndex = null;
        ir2md.classLayoutEntries = null;
        ir2md.constantTableEntries = null;
        ir2md.documentMap = null;
        ir2md.eventEntries = null;
        ir2md.eventIndex = null;
        ir2md.eventMapEntries = null;
        ir2md.eventMapIndex = null;
        ir2md.exceptionBlock = null;
        ir2md.fieldEntries = null;
        ir2md.fieldIndex = null;
        ir2md.fieldLayoutEntries = null;
        ir2md.fieldRvaEntries = null;
        ir2md.fileTableEntries = null;
        ir2md.fileTableIndex = null;
        ir2md.genericParamConstraintEntries = null;
        ir2md.genericParamEntries = null;
        ir2md.genericParameters = null;
        ir2md.genericParamIndex = null;
        ir2md.guidEntries = null;
        ir2md.guidIndex = null;
        ir2md.implMapEntries = null;
        ir2md.interfaceEntries = null;
        ir2md.marshalEntries = null;
        ir2md.memberRefEntries = null;
        ir2md.memberRefIndex = null;
        ir2md.methodBodiesHeap = null;
        ir2md.methodBodiesHeapIndex = null;
        ir2md.methodBodyHeap = null;
        ir2md.methodEntries = null;
        ir2md.methodImplEntries = null;
        ir2md.methodIndex = null;
        ir2md.methodInfo = null;
#if !MinimalReader && !CodeContracts
        ir2md.currentMethod = null;
#endif
        ir2md.methodSemanticsEntries = null;
        ir2md.methodSpecEntries = null;
        ir2md.methodSpecIndex = null;
        ir2md.module = null;
        ir2md.moduleRefEntries = null;
        ir2md.moduleRefIndex = null;
        ir2md.nestedClassEntries = null;
        ir2md.nodesWithCustomAttributes = null;
        ir2md.nodesWithSecurityAttributes = null;
        ir2md.paramEntries = null;
        ir2md.paramIndex = null;
        ir2md.propertyEntries = null;
        ir2md.propertyIndex = null;
        ir2md.propertyMapEntries = null;
        ir2md.propertyMapIndex = null;
        ir2md.PublicKey = null;
        ir2md.resourceDataHeap = null;
        ir2md.sdataHeap = null;
        ir2md.standAloneSignatureEntries = null;
        ir2md.stringHeap = null;
        ir2md.stringHeapIndex = null;
#if !ROTOR
        ir2md.symWriter = null;
#endif
        ir2md.tlsHeap = null;
        ir2md.typeDefEntries = null;
        ir2md.typeDefIndex = null;
        ir2md.typeParameterNumber = null;
        ir2md.typeRefEntries = null;
        ir2md.typeRefIndex = null;
        ir2md.typeSpecEntries = null;
        ir2md.typeSpecIndex = null;
        ir2md.unspecializedFieldFor = null;
        ir2md.unspecializedMethodFor = null;
        ir2md.userStringHeap = null;
        ir2md.userStringHeapIndex = null;
        ir2md.writer = null;
        ir2md = null;
      }
    }

    private static Guid IID_IUnknown      = new Guid("00000000-0000-0000-C000-000000000046");
    private static Guid IID_IClassFactory = new Guid("00000001-0000-0000-C000-000000000046");

    [ComImport(), Guid("00000001-0000-0000-C000-000000000046"), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    interface IClassFactory {
         int CreateInstance(
                [In, MarshalAs(UnmanagedType.Interface)] object unused,
                [In] ref Guid refiid,
                [MarshalAs(UnmanagedType.Interface)] out Object ppunk);
         int LockServer(
                int fLock);
    }

    delegate int GetClassObjectDelegate([In] ref Guid refclsid,
                                        [In] ref Guid refiid,
                                        [MarshalAs(UnmanagedType.Interface)] out IClassFactory ppUnk);

    [DllImport("kernel32.dll", CharSet=CharSet.Ansi)]
    private static extern int LoadLibrary(string lpFileName);
    [DllImport("kernel32.dll", CharSet=CharSet.Ansi)]
    private static extern GetClassObjectDelegate GetProcAddress(int hModule, string lpProcName);

    private static object CrossCompileActivate(string server, Guid guid){
      // Poor man's version of Activator.CreateInstance or CoCreate
      object o = null;
      int hmod = LoadLibrary(server);
      if (hmod != 0){
        GetClassObjectDelegate del = GetProcAddress(hmod, "DllGetClassObject");
        if (del != null) {
          IClassFactory icf;
          int hr = del(ref guid, ref IID_IClassFactory, out icf);
          if (hr == 0 && icf != null){
            object temp = null;
            hr = icf.CreateInstance(null, ref IID_IUnknown, out temp);
            if (hr == 0) o = temp;
          }
        }
      }
      return o;
    }
    private void SetupMetadataWriter(string debugSymbolsLocation){
      Version v = TargetPlatform.TargetVersion;
      this.UseGenerics = TargetPlatform.UseGenerics;
#if !ROTOR
      if (debugSymbolsLocation != null){
        // If targeting RTM (Version.Major = 1 and Version.Minor = 0)
        // then use Symwriter.pdb as ProgID else use CorSymWriter_SxS
        // (Note that RTM version 1.0.3705 has Assembly version 1.0.3300,
        // hence the <= 3705 expression.  This also leaves room for RTM SP releases
        // with slightly different build numbers).
        Type t = null;
        if (v.Major == 1 && v.Minor == 0 && v.Build <= 3705){
          try{
            t = Type.GetTypeFromProgID("Symwriter.pdb", false);
            this.symWriter = (ISymUnmanagedWriter)Activator.CreateInstance(t);
            if (this.symWriter != null)
              this.symWriter.Initialize(this, debugSymbolsLocation, null, true);            
          }catch (Exception){
            t = null;
            this.symWriter = null;
          }
        }
        if (t == null){
          Debug.Assert(this.symWriter == null);
          t = Type.GetTypeFromProgID("CorSymWriter_SxS", false);
          if (t != null) {
            Guid guid = t.GUID;

            // If the compiler was built with Whidbey, then mscoree will pick a matching
            // diasymreader.dll out of the Whidbey directory.  But if we are cross-
            // compiling, this is *NOT* what we want.  Instead, we want to override
            // the shim's logic and explicitly pick a diasymreader.dll from the place
            // that matches the version of the output file we are emitting.  This is
            // strictly illegal by the CLR's rules.  However, the CLR does not yet
            // support cross-compilation, so we have little choice.
            if (!UseGenerics) {
              Version vcompiler = typeof(object).Assembly.GetName().Version;
              if (vcompiler.Major >= 2) {
                // This is the only cross-compilation case we currently support.
                string server = Path.Combine(Path.GetDirectoryName(typeof(object).Assembly.Location),
                                                                 "..\\v1.1.4322\\diasymreader.dll");
                object o = CrossCompileActivate(server, guid);
                this.symWriter = (ISymUnmanagedWriter)o;
              }
            }
            if (this.symWriter == null) {
              this.symWriter = (ISymUnmanagedWriter)Activator.CreateInstance(t);
            }
            if (this.symWriter != null)
              this.symWriter.Initialize(this, debugSymbolsLocation, null, true);
          } else {
            throw new DebugSymbolsCouldNotBeWrittenException();
          }
        }
      }
#endif
      //Visit the module, building lists etc.
      this.VisitModule(this.module);
      //Use the lists to populate the tables in the metadata writer
#if !ROTOR
      MetadataWriter writer = this.writer = new MetadataWriter(this.symWriter);
#else
      MetadataWriter writer = this.writer = new MetadataWriter();
#endif
      writer.UseGenerics = this.UseGenerics;
      if (module.EntryPoint != null){
        writer.entryPointToken = this.GetMethodToken(module.EntryPoint);
#if !ROTOR
        if (this.symWriter != null) this.symWriter.SetUserEntryPoint((uint)writer.entryPointToken);
#endif
      }
      writer.dllCharacteristics = module.DllCharacteristics;
      writer.moduleKind = module.Kind;
      writer.peKind = module.PEKind;
      writer.TrackDebugData = module.TrackDebugData;
      writer.fileAlignment = module.FileAlignment;
      writer.baseAddress = module.BaseAddress;
      writer.sizeOfStackReserve = module.SizeOfStackReserve;
      if (writer.fileAlignment < 512) writer.fileAlignment = 512;
      writer.PublicKey = this.PublicKey;
      writer.SignatureKeyLength = this.SignatureKeyLength;
      if (this.assembly != null) this.PopulateAssemblyTable();
      this.PopulateClassLayoutTable();
      this.PopulateConstantTable();
      this.PopulateGenericParamTable(); //Needs to happen before PopulateCustomAttributeTable since it the latter refers to indices in the sorted table
      this.PopulateCustomAttributeTable();
      this.PopulateDeclSecurityTable();
      this.PopulateEventMapTable();
      this.PopulateEventTable();
      this.PopulateExportedTypeTable();
      this.PopulateFieldTable();
      this.PopulateFieldLayoutTable();
      this.PopulateFieldRVATable();
      this.PopulateManifestResourceTable(); //This needs to happen before PopulateFileTable because resources are not visited separately
      this.PopulateFileTable();
      this.PopulateGenericParamConstraintTable();
      this.PopulateImplMapTable();
      this.PopulateInterfaceImplTable();
      this.PopulateMarshalTable();
      this.PopulateMethodTable();
      this.PopulateMethodImplTable();
      this.PopulateMemberRefTable();
      this.PopulateMethodSemanticsTable();
      this.PopulateMethodSpecTable();
      this.PopulateModuleTable();
      this.PopulateModuleRefTable();
      this.PopulateNestedClassTable();
      this.PopulateParamTable();
      this.PopulatePropertyTable();
      this.PopulatePropertyMapTable();
      this.PopulateStandAloneSigTable();
      this.PopulateTypeDefTable();
      this.PopulateTypeRefTable();
      this.PopulateTypeSpecTable();
      this.PopulateGuidTable();
      this.PopulateAssemblyRefTable();
      this.writer.BlobHeap = (MemoryStream)this.blobHeap.BaseStream; //this.blobHeap = null;
      this.writer.SdataHeap = (MemoryStream)this.sdataHeap.BaseStream; //this.sdataHeap = null;
      this.writer.TlsHeap = (MemoryStream)this.tlsHeap.BaseStream; //this.tlsHeap = null;
      this.writer.StringHeap = (MemoryStream)this.stringHeap.BaseStream; //this.stringHeap = null;
      this.writer.UserstringHeap = (MemoryStream)this.userStringHeap.BaseStream; //this.userStringHeap = null;
      this.writer.MethodBodiesHeap = (MemoryStream)this.methodBodiesHeap.BaseStream; //this.methodBodiesHeap = null;
      this.writer.ResourceDataHeap = (MemoryStream)this.resourceDataHeap.BaseStream; //this.resourceDataHeap = null;
      this.writer.Win32Resources = this.module.Win32Resources;
    }
    int GetAssemblyRefIndex(AssemblyNode/*!*/ assembly) {
      if (assembly.Location == "unknown:location")
        throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
          ExceptionStrings.UnresolvedAssemblyReferenceNotAllowed, assembly.Name));
      Object index = this.assemblyRefIndex[assembly.UniqueKey];
      if (index == null){
        index = this.assemblyRefEntries.Count+1;
        AssemblyReference aref = new AssemblyReference(assembly);
        if (this.module.UsePublicKeyTokensForAssemblyReferences){
          aref.PublicKeyOrToken = aref.PublicKeyToken;
          aref.HashValue = null;
          aref.Flags = aref.Flags & ~AssemblyFlags.PublicKey;
        }

        // make sure that written flags are ECMA compatible
        aref.Flags = aref.Flags & (AssemblyFlags.PublicKey | AssemblyFlags.Retargetable | AssemblyFlags.DisableJITcompileOptimizer | AssemblyFlags.EnableJITcompileTracking);

        this.assemblyRefEntries.Add(aref);
        this.assemblyRefIndex[assembly.UniqueKey] = index;
      }
      return (int)index;
    }
    int GetBlobIndex(ExpressionList expressions, ParameterList parameters){
      MemoryStream sig = new MemoryStream();
      BinaryWriter signature = new BinaryWriter(sig);
      this.WriteCustomAttributeSignature(expressions, parameters, false, signature);
      byte[] sigBytes = sig.ToArray();
      int length = sigBytes.Length;
      int index = (int)this.blobHeap.BaseStream.Position;
      Ir2md.WriteCompressedInt(this.blobHeap, length);
      this.blobHeap.BaseStream.Write(sigBytes, 0, length);
      return index;
    }
    void WriteCustomAttributeSignature(ExpressionList expressions, ParameterList parameters, bool onlyWriteNamedArguments, BinaryWriter signature) {
      int n = parameters == null ? 0 : parameters.Count;
      int m = expressions == null ? 0 : expressions.Count;
      Debug.Assert(m >= n);
      int numNamed = m > n ? m - n : 0;
      if (onlyWriteNamedArguments) {
        Ir2md.WriteCompressedInt(signature, numNamed);
      }else{
        signature.Write((short)1);
        if (parameters != null && expressions != null) {
          for (int i = 0; i < n; i++) {
            Parameter p = parameters[i];
            Expression e = expressions[i];
            if (p == null || e == null) continue;
            Literal l = e as Literal;
            if (l == null) { Debug.Assert(false); continue; }
            this.WriteCustomAttributeLiteral(signature, l, p.Type == CoreSystemTypes.Object);
          }
        }
        signature.Write((short)numNamed);
      }
      if (expressions != null) {
        for (int i = n; i < m; i++) {
          Expression e = expressions[i];
          NamedArgument narg = e as NamedArgument;
          if (narg == null) { Debug.Assert(false); continue; }
          signature.Write((byte)(narg.IsCustomAttributeProperty ? 0x54 : 0x53));
          if (narg.ValueIsBoxed)
            signature.Write((byte)ElementType.BoxedEnum);
          else if (narg.Value.Type is EnumNode) {
            signature.Write((byte)ElementType.Enum);
            this.WriteSerializedTypeName(signature, narg.Value.Type);
          } else if (narg.Value.Type == CoreSystemTypes.Type)
            signature.Write((byte)ElementType.Type);
          else if (narg.Value.Type is ArrayType) {
            ArrayType arrT = (ArrayType)narg.Value.Type;
            if (arrT.ElementType == CoreSystemTypes.Type) {
              signature.Write((byte)ElementType.SzArray);
              signature.Write((byte)ElementType.Type);
            } else {
              if (arrT.ElementType is EnumNode) {
                signature.Write((byte)ElementType.SzArray);
                signature.Write((byte)ElementType.Enum);
                this.WriteSerializedTypeName(signature, arrT.ElementType);
              } else {
                this.WriteTypeSignature(signature, narg.Value.Type);
              }
            }
          } else
            this.WriteTypeSignature(signature, narg.Value.Type);
          signature.Write(narg.Name.Name, false);
          this.WriteCustomAttributeLiteral(signature, (Literal)narg.Value, narg.ValueIsBoxed);
        }
      }
    }
    int GetBlobIndex(byte[]/*!*/ blob) {
      object indexOb = this.blobHeapIndex[blob];
      if (indexOb != null) return (int)indexOb;
      int index = (int)this.blobHeap.BaseStream.Position;
      int length = blob.Length;
      Ir2md.WriteCompressedInt(this.blobHeap, length);
      this.blobHeap.BaseStream.Write(blob, 0, length);
      this.blobHeapIndex[blob] = index;
      return index;
    }
    int GetBlobIndex(string/*!*/ str) {
      object indexOb = this.blobHeapStringIndex[str];
      if (indexOb != null) return (int)indexOb;
      int index = (int)this.blobHeap.BaseStream.Position;
      this.blobHeap.Write((string)str);
      this.blobHeapStringIndex[str] = index;
      return index;
    }
    int GetBlobIndex(Field/*!*/ field) {
      if (field != null && field.DeclaringType != null && field.DeclaringType.Template != null && field.DeclaringType.Template.IsGeneric)
        field = this.GetUnspecializedField(field);
      MemoryStream sig = new MemoryStream();
      BinaryWriter signature = new BinaryWriter(sig);
      signature.Write((byte)0x6);
      TypeNode fieldType = field.Type;
      if (field.IsVolatile && !(fieldType is RequiredModifier) && SystemTypes.IsVolatile != null)
      {
        fieldType = RequiredModifier.For(SystemTypes.IsVolatile, fieldType);
      }
#if ExtendedRuntime
      if (field.HasOutOfBandContract) fieldType = TypeNode.DeepStripModifiers(fieldType, null, SystemTypes.NonNullType);
#endif
      if (fieldType == null) { Debug.Fail(""); fieldType = SystemTypes.Object; }
      this.WriteTypeSignature(signature, fieldType, true);
      return this.GetBlobIndex(sig.ToArray());
    }
    int GetBlobIndex(MarshallingInformation/*!*/ marshallingInformation) {
      MemoryStream sig = new MemoryStream();
      BinaryWriter signature = new BinaryWriter(sig);
      signature.Write((byte)marshallingInformation.NativeType);
      switch (marshallingInformation.NativeType){
        case NativeType.SafeArray:
          signature.Write((byte)marshallingInformation.ElementType);
          if (marshallingInformation.Class != null && marshallingInformation.Class.Length > 0)
            signature.Write(marshallingInformation.Class, false);
          break;
        case NativeType.LPArray:
          signature.Write((byte)marshallingInformation.ElementType);
          if (marshallingInformation.ParamIndex >= 0 || marshallingInformation.ElementSize > 0) {
            if (marshallingInformation.ParamIndex < 0) {
              Debug.Fail("MarshallingInformation.ElementSize > 0 should imply that ParamIndex >= 0");
              marshallingInformation.ParamIndex = 0;
            }
            Ir2md.WriteCompressedInt(signature, marshallingInformation.ParamIndex);
          }
          if (marshallingInformation.ElementSize > 0){
            Ir2md.WriteCompressedInt(signature, marshallingInformation.ElementSize);
            if (marshallingInformation.NumberOfElements > 0)
              Ir2md.WriteCompressedInt(signature, marshallingInformation.NumberOfElements);
          }
          break;
        case NativeType.ByValArray:
          Ir2md.WriteCompressedInt(signature, marshallingInformation.Size);
          if (marshallingInformation.ElementType != NativeType.NotSpecified)
            signature.Write((byte)marshallingInformation.ElementType);
          break;
        case NativeType.ByValTStr:
          Ir2md.WriteCompressedInt(signature, marshallingInformation.Size);
          break;
        case NativeType.Interface:
          if (marshallingInformation.Size > 0)
            Ir2md.WriteCompressedInt(signature, marshallingInformation.Size);
          break;
        case NativeType.CustomMarshaler:
          signature.Write((short)0);
          signature.Write(marshallingInformation.Class);
          signature.Write(marshallingInformation.Cookie);
          break;
      }
      return this.GetBlobIndex(sig.ToArray());
    }
    int GetBlobIndex(Literal/*!*/ literal) {
      int index = (int)this.blobHeap.BaseStream.Position;
      TypeNode lType = literal.Type;
      EnumNode eType = lType as EnumNode;
      if (eType != null) lType = eType.UnderlyingType;
      IConvertible ic = literal.Value as IConvertible;
      if (ic == null) ic = "";
      switch(lType.typeCode){
        case ElementType.Boolean: this.blobHeap.Write((byte)1); this.blobHeap.Write(ic.ToBoolean(null)); break;
        case ElementType.Char: this.blobHeap.Write((byte)2); this.blobHeap.Write(ic.ToChar(null)); break;
        case ElementType.Int8: this.blobHeap.Write((byte)1); this.blobHeap.Write(ic.ToSByte(null)); break;
        case ElementType.UInt8: this.blobHeap.Write((byte)1); this.blobHeap.Write(ic.ToByte(null)); break;
        case ElementType.Int16: this.blobHeap.Write((byte)2); this.blobHeap.Write(ic.ToInt16(null)); break;
        case ElementType.UInt16: this.blobHeap.Write((byte)2); this.blobHeap.Write(ic.ToUInt16(null)); break;
        case ElementType.Int32: this.blobHeap.Write((byte)4); this.blobHeap.Write(ic.ToInt32(null)); break;
        case ElementType.UInt32: this.blobHeap.Write((byte)4); this.blobHeap.Write(ic.ToUInt32(null)); break;
        case ElementType.Int64: this.blobHeap.Write((byte)8); this.blobHeap.Write(ic.ToInt64(null)); break;
        case ElementType.UInt64: this.blobHeap.Write((byte)8); this.blobHeap.Write(ic.ToUInt64(null)); break;
        case ElementType.Single: this.blobHeap.Write((byte)4); this.blobHeap.Write(ic.ToSingle(null)); break;
        case ElementType.Double: this.blobHeap.Write((byte)8); this.blobHeap.Write(ic.ToDouble(null)); break;
        case ElementType.String: this.blobHeap.Write((string)literal.Value, false); break;
        case ElementType.Array:
        case ElementType.Class:
        case ElementType.Object:
        case ElementType.Reference:
        case ElementType.SzArray: this.blobHeap.Write((byte)4); this.blobHeap.Write((int)0); break; //REVIEW: standard implies this should be 0, peverify thinks otherwise.
        default: Debug.Assert(false, "Unexpected Literal type"); return 0;
      }
      return index;
    }
    int GetBlobIndex(FunctionPointer/*!*/ fp) {
      MemoryStream sig = new MemoryStream();
      BinaryWriter signature = new BinaryWriter(sig);
      this.WriteMethodSignature(signature, fp);
      return this.GetBlobIndex(sig.ToArray());
    }
    int GetBlobIndex(Method/*!*/ method, bool methodSpecSignature) {
      MemoryStream sig = new MemoryStream();
      BinaryWriter signature = new BinaryWriter(sig);
      if (methodSpecSignature)
        this.WriteMethodSpecSignature(signature, method);
      else
        this.WriteMethodSignature(signature, method);
      return this.GetBlobIndex(sig.ToArray());
    }
    int GetBlobIndex(AttributeList/*!*/ securityAttributes) {
      MemoryStream sig = new MemoryStream();
      BinaryWriter signature = new BinaryWriter(sig);
      signature.Write((byte)'.');
      Ir2md.WriteCompressedInt(signature, securityAttributes.Count);
      foreach (AttributeNode attr in securityAttributes)
        this.WriteSecurityAttribute(signature, attr);
      return this.GetBlobIndex(sig.ToArray());
    }
    private void WriteSecurityAttribute(BinaryWriter signature, AttributeNode attr) {
      bool isAssemblyQualified = true;
      string attrTypeName = this.GetSerializedTypeName(attr.Type, ref isAssemblyQualified);
      if (!isAssemblyQualified) {
        attrTypeName += ", "+attr.Type.DeclaringModule.ContainingAssembly.StrongName;
      }
      signature.Write(attrTypeName);
      MemoryStream sig = new MemoryStream();
      BinaryWriter casig = new BinaryWriter(sig);
      MemberBinding mb = attr.Constructor as MemberBinding;
      if (mb == null) return;
      InstanceInitializer constructor = mb.BoundMember as InstanceInitializer;
      if (constructor == null) return;
      this.WriteCustomAttributeSignature(attr.Expressions, constructor.Parameters, true, casig);
      byte[] sigBytes = sig.ToArray();
      int length = sigBytes.Length;
      Ir2md.WriteCompressedInt(signature, length);
      signature.BaseStream.Write(sigBytes, 0, length);
    }
    int GetBlobIndex(Property/*!*/ prop) {
      MemoryStream sig = new MemoryStream();
      BinaryWriter signature = new BinaryWriter(sig);
      this.WritePropertySignature(signature, prop);
      return this.GetBlobIndex(sig.ToArray());
    }
    int GetBlobIndex(TypeNode/*!*/ type) {
      MemoryStream sig = new MemoryStream();
      BinaryWriter signature = new BinaryWriter(sig);
      this.WriteTypeSignature(signature, type, true);
      return this.GetBlobIndex(sig.ToArray());
    }
    int GetCustomAttributeParentCodedIndex(Node/*!*/ node) {
      switch(node.NodeType){
        case NodeType.InstanceInitializer:
        case NodeType.StaticInitializer:
        case NodeType.Method: return this.GetMethodIndex((Method)node)<<5;
        case NodeType.Field: return (this.GetFieldIndex((Field)node)<<5)|1;
        case NodeType.Parameter: return (this.GetParamIndex((Parameter)node)<<5)|4;
        case NodeType.Class:
        case NodeType.DelegateNode:
        case NodeType.EnumNode:
        case NodeType.Interface:
        case NodeType.Struct:
#if !MinimalReader
        case NodeType.TupleType:
        case NodeType.TypeAlias:
        case NodeType.TypeIntersection:
        case NodeType.TypeUnion:
#endif
          TypeNode t = (TypeNode)node;
          if (this.IsStructural(t) && (!t.IsGeneric || (t.Template != null && t.ConsolidatedTemplateArguments != null && t.ConsolidatedTemplateArguments.Count > 0)))
            return (this.GetTypeSpecIndex(t) << 5) | 13;
          else
            return (this.GetTypeDefIndex(t) << 5) | 3;
        case NodeType.ClassParameter:
        case NodeType.TypeParameter: 
          if (!this.UseGenerics) goto case NodeType.Class;
          return (this.GetGenericParamIndex((TypeNode)node)<<5)|19;
        case NodeType.Property: return (this.GetPropertyIndex((Property)node)<<5)|9;
        case NodeType.Event: return (this.GetEventIndex((Event)node)<<5)|10;
        case NodeType.Module: return (1 << 5) | 7;
        case NodeType.Assembly: return (1 << 5) | 14;
        default: Debug.Assert(false, "Unexpect custom attribute parent"); return 0;
      }
    }
#if !ROTOR
    ISymUnmanagedDocumentWriter GetDocumentWriter(Document/*!*/ doc) 
      //^ requires this.symWriter != null;
    {
      int key = Identifier.For(doc.Name).UniqueIdKey;
      object writer = this.documentMap[key];
      if (writer == null){
        writer = this.symWriter.DefineDocument(doc.Name, ref doc.Language, ref doc.LanguageVendor, ref doc.DocumentType);
        this.documentMap[key] = writer;
      }
      return (ISymUnmanagedDocumentWriter)writer;
    }

    ISymUnmanagedDocumentWriter GetArbitraryDocWriter()
    //^ requires this.symWriter != null;
    {
      foreach (var writer in this.documentMap.Values)
      {
        return (ISymUnmanagedDocumentWriter)writer;
      }
      return null;
    }

#endif
    int GetEventIndex(Event/*!*/ e) {
      return (int)this.eventIndex[e.UniqueKey];
    }
    int GetFieldIndex(Field/*!*/ f) {
      Object index = this.fieldIndex[f.UniqueKey];
      if (index == null){
        if (this.fieldEntries == null) return 1;
        index = this.fieldEntries.Count+1;
        this.fieldEntries.Add(f);
        this.fieldIndex[f.UniqueKey] = index;
        if (f.DefaultValue != null && !(f.DefaultValue.Value is Parameter))
          this.constantTableEntries.Add(f);
        if (!f.IsStatic && f.DeclaringType != null && (f.DeclaringType.Flags & TypeFlags.ExplicitLayout) != 0)
          this.fieldLayoutEntries.Add(f);
        if ((f.Flags & FieldFlags.HasFieldRVA) != 0)
          this.fieldRvaEntries.Add(f);
        if (f.MarshallingInformation != null)
          this.marshalEntries.Add(f);
      }
      return (int)index;
    }
    int GetGenericParamIndex(TypeNode/*!*/ gp) {
      return (int)this.genericParamIndex[gp.UniqueKey];
    }
    int GetFieldToken(Field/*!*/ f) {
      if (f.DeclaringType == null || (f.DeclaringType.DeclaringModule == this.module && !this.IsStructural(f.DeclaringType)))
        return 0x04000000 | this.GetFieldIndex(f);
      else
        return 0x0a000000 | this.GetMemberRefIndex(f);
    }
    bool IsStructural(TypeNode type){
      if (type == null) return false;
      if (this.UseGenerics && (type.IsGeneric || type.Template != null && type.Template.IsGeneric)) return true;
      switch (type.NodeType){
        case NodeType.ArrayType:
        case NodeType.Pointer:
        case NodeType.Reference:
        case NodeType.OptionalModifier:
        case NodeType.RequiredModifier:
          return true;
        case NodeType.ClassParameter:
        case NodeType.TypeParameter:
          return this.UseGenerics;
      }
      return false;
    }
    int GetFileTableIndex(Module/*!*/ module) {
      Object index = this.fileTableIndex[module];
      if (index == null){
        index = this.fileTableEntries.Count+1;
        this.fileTableEntries.Add(module);
        this.fileTableIndex[module] = index;
      }
      return (int)index;
    }
    int GetGuidIndex(Guid guid){
      Object index = this.guidIndex[guid];
      if (index == null){
        index = this.guidEntries.Count+1;
        this.guidEntries.Add(guid);
        this.guidIndex[guid] = index;
      }
      return (int)index;
    }
    internal int GetLocalVarIndex(Local/*!*/ loc) {
#if !MinimalReader
      LocalBinding lb = loc as LocalBinding;
      if (lb != null) loc = lb.BoundLocal;
#endif
      if (this.StripOptionalModifiersFromLocals)
        loc.Type = TypeNode.StripModifiers(loc.Type);
      MethodInfo methInfo = this.methodInfo;
      
      if (methInfo.localVarSignature == null){
        methInfo.localVarSignature = new BinaryWriter(new MemoryStream());
        methInfo.localVarSignature.Write((short)0);
        methInfo.localVarIndex = new TrivialHashtable<int>();
        methInfo.localVarSigTok = 0x11000000 | this.GetStandAloneSignatureIndex(methInfo.localVarSignature);
      }
#if true
      int index;
      if (!methInfo.localVarIndex.TryGetValue(loc.UniqueKey, out index)) {
#else
      object index = methInfo.localVarIndex[loc.UniqueKey];
      if (index == null) {
#endif
        methInfo.localVarIndex[loc.UniqueKey] = index = methInfo.localVarIndex.Count;
#if !ROTOR
        int startPosition = 0;
        if (this.symWriter != null && loc.Name != null && loc.Name.UniqueIdKey != Identifier.Empty.UniqueIdKey){
          methInfo.debugLocals.Add(loc);
          methInfo.signatureOffsets.Add(startPosition = methInfo.localVarSignature.BaseStream.Position);
          if (loc.Pinned) methInfo.localVarSignature.Write((byte)ElementType.Pinned);
          this.WriteTypeSignature(methInfo.localVarSignature, loc.Type, true);
          methInfo.signatureLengths.Add(methInfo.localVarSignature.BaseStream.Position - startPosition);
        }else{
#endif
          if (loc.Pinned) methInfo.localVarSignature.Write((byte)ElementType.Pinned);
          this.WriteTypeSignature(methInfo.localVarSignature, loc.Type, true);
#if !ROTOR
        }
#endif
      }
      return (int)index;
    }
    int GetMemberRefParentEncoded(TypeNode type){
      if (type == null) return 0;
      if (this.IsStructural(type)) return (this.GetTypeSpecIndex(type) << 3) | 4;
      if (type.DeclaringModule == this.module) return this.GetTypeDefIndex(type) << 3;
      if (type.DeclaringModule != null) return (this.GetTypeRefIndex(type) << 3)|1;
      if (type.typeCode == ElementType.Class || type.typeCode == ElementType.ValueType)
        return this.GetTypeDefIndex(type) << 3; //REVIEW: when does this happen?
      Debug.Assert(false);
      return 0;
    }
    int GetMemberRefIndex(Member/*!*/ m) {
      int index;
      if (!this.memberRefIndex.TryGetValue(m.UniqueKey, out index))
      {
        index = this.memberRefEntries.Count+1;
        this.memberRefEntries.Add(m);
        this.memberRefIndex[m.UniqueKey] = index;
        TypeNode type = m.DeclaringType;
        this.VisitReferencedType(type);
      }
      return index;
    }
    class VarargMethodCallSignature : FunctionPointer{
      internal Method method;
      internal VarargMethodCallSignature(Method/*!*/ method, TypeNodeList/*!*/ parameterTypes)
        : base(parameterTypes, method.ReturnType, method.Name){
        this.method = method;
        this.DeclaringType = method.DeclaringType;
      }
    }
    int GetMemberRefToken(Method/*!*/ m, ExpressionList arguments) {
      int numArgs = arguments == null ? 0 : arguments.Count;
      TypeNodeList parTypes = new TypeNodeList(numArgs);
      int varArgStart = m.Parameters.Count;
      for (int i = 0; i < varArgStart; i++) 
        parTypes.Add(m.Parameters[i].Type);
      for (int i = varArgStart; i < numArgs; i++) {
        //^ assert arguments != null;
        parTypes.Add(arguments[i].Type);               
      }      
      VarargMethodCallSignature sig = new VarargMethodCallSignature(m, parTypes);
      sig.VarArgStart = varArgStart;
      sig.CallingConvention = m.CallingConvention;
      return 0x0a000000 | this.GetMemberRefIndex(sig);
    }
    int GetMethodDefOrRefEncoded(Method/*!*/ m) {
      if (m.DeclaringType.DeclaringModule == this.module && !this.IsStructural(m.DeclaringType))
        return this.GetMethodIndex(m) << 1;
      else
        return (this.GetMemberRefIndex(m) << 1)|0x1;
    }
    int GetMethodIndex(Method/*!*/ m) {
      int index;
      if (!this.methodIndex.TryGetValue(m.UniqueKey, out index)){
        if (this.methodEntries == null) return 1;
        index = this.methodEntries.Count+1;
        this.methodEntries.Add(m);
        this.methodIndex[m.UniqueKey] = index;
        if (m.ReturnTypeMarshallingInformation != null || (m.ReturnAttributes != null && m.ReturnAttributes.Count > 0)){
          Parameter p = new Parameter();
          p.ParameterListIndex = -1;
          p.Attributes = m.ReturnAttributes;
          if (m.ReturnTypeMarshallingInformation != null){
            p.MarshallingInformation = m.ReturnTypeMarshallingInformation;
            p.Flags = ParameterFlags.HasFieldMarshal;
            this.marshalEntries.Add(p);
          }
          this.paramEntries.Add(p);
          this.paramIndex[m.UniqueKey] = this.paramEntries.Count;
          this.paramIndex[p.UniqueKey] = this.paramEntries.Count;
          this.VisitAttributeList(p.Attributes, p);
        }
        int offset = m.IsStatic ? 0 : 1;
        if (m.Parameters != null){
          for (int i = 0, n = m.Parameters.Count; i < n; i++){
            Parameter p = m.Parameters[i];
            if (p == null) continue;
            if (p == null) continue;
            if (p.DeclaringMethod == null) p.DeclaringMethod = m;
            p.ParameterListIndex = i;
            p.ArgumentListIndex = i+offset;
            int j = this.paramEntries.Count+1;
            this.paramEntries.Add(p); //TODO: provide a way to suppress the param table entries unless param has custom attributes or flags
            this.paramIndex[p.UniqueKey] = j;
            if (p.DefaultValue != null)
              this.constantTableEntries.Add(p);
            if (p.MarshallingInformation != null)
              this.marshalEntries.Add(p);
          }
        }
        if (m.IsGeneric)
          this.VisitGenericParameterList(m, m.TemplateParameters);
      }
      return index;
    }
    int GetMethodSpecIndex(Method/*!*/ m) {
      int structuralKey = m.UniqueKey;
      int blobIndex = this.GetBlobIndex(m, true);
      if (m.Template != null)
        structuralKey = (m.Template.UniqueKey << 8) + blobIndex;
      else
        Debug.Assert(false);
      Object index = this.methodSpecIndex[m.UniqueKey];
      if (index == null){
        index = this.methodSpecIndex[structuralKey];
        if (index is int){
          Method otherMethod = this.methodSpecEntries[((int)index)-1];
          if (otherMethod != null && otherMethod.Template == m.Template && blobIndex == this.GetBlobIndex(otherMethod, true))
            return (int)index;
        }
        index = this.methodSpecEntries.Count+1;
        this.methodSpecEntries.Add(m);
        this.methodSpecIndex[m.UniqueKey] = index;
        this.methodSpecIndex[structuralKey] = index;
        this.GetMemberRefIndex(m.Template);
        Method templ = m.Template;
        if (templ != null){
          while (templ.Template != null) templ = templ.Template;
          TypeNodeList templParams = templ.TemplateParameters;
          if (templParams != null) {
            for (int i = 0, n = templParams.Count; i < n; i++) {
              TypeNode templParam = templParams[i];
              if (templParam == null) continue;
              this.typeParameterNumber[templParam.UniqueKey] = -(i+1);
            }
          }
        }
      }
      return (int)index;
    }
    int GetMethodToken(Method/*!*/ m) {
      if (this.UseGenerics && m.Template != null && m.Template.IsGeneric)
        return 0x2b000000 | this.GetMethodSpecIndex(m);
      else if (m.DeclaringType.DeclaringModule == this.module && !this.IsStructural(m.DeclaringType))
        return 0x06000000 | this.GetMethodIndex(m);
      else
        return 0x0a000000 | this.GetMemberRefIndex(m);
    }
    internal int GetMethodDefToken(Method/*!*/ m) {
      if (m.DeclaringType.DeclaringModule == this.module)
        return 0x06000000 | this.GetMethodIndex(m);
      else
        return 0x0a000000 | this.GetMemberRefIndex(m);
    }
    int GetMethodBodiesHeapIndex(Method/*!*/ m) {
      return (int)this.methodBodiesHeapIndex[m.UniqueKey];
    }
    int GetModuleRefIndex(Module/*!*/ module) {
      if (module.Location == "unknown:location") throw new InvalidOperationException(ExceptionStrings.UnresolvedModuleReferenceNotAllowed);
      Object index = this.moduleRefIndex[module.Name];
      if (index == null){
        index = this.moduleRefEntries.Count+1;
        this.moduleRefEntries.Add(new ModuleReference(module.Name, module));
        this.moduleRefIndex[module.Name] = index;
        if (module.HashValue != null && module.HashValue.Length > 0)
          this.GetFileTableIndex(module);
      }
      return (int)index;
    }
    int GetOffset(Block target, int addressOfNextInstruction){
      if (target == null) return 0;
      int fixupLocation = (int)(this.methodBodyHeap.BaseStream.Position);
      Object ob = this.methodInfo.fixupIndex[target.UniqueKey];
      if (ob is int) return ((int)ob) - addressOfNextInstruction;
      Fixup fixup = new Fixup();
      fixup.addressOfNextInstruction = addressOfNextInstruction;
      fixup.fixupLocation = fixupLocation;
      fixup.shortOffset = false;
      fixup.nextFixUp = (Fixup)ob;
      this.methodInfo.fixupIndex[target.UniqueKey] = fixup;
      return 0;
    }
    int GetOffset(Block target, ref bool shortOffset){
      if (target == null) return 0;
      int fixupLocation = (int)(this.methodBodyHeap.BaseStream.Position+1);
      Object ob = this.methodInfo.fixupIndex[target.UniqueKey];
      if (ob is int){
        int targetAddress = (int)ob;
        int offset = targetAddress - (fixupLocation+1);
        if (-128 > offset || offset > 127){
          offset = targetAddress - (fixupLocation+4);
          Debug.Assert(offset < -128, "Forward short branch out of range");
          shortOffset = false;
        }else
          shortOffset = true;
        return offset;
      }
      Fixup fixup = new Fixup();
      fixup.fixupLocation = fixup.addressOfNextInstruction = fixupLocation;
      if (shortOffset) fixup.addressOfNextInstruction+=1; else fixup.addressOfNextInstruction+=4;
      fixup.shortOffset = shortOffset;
      fixup.nextFixUp = (Fixup)ob;
      this.methodInfo.fixupIndex[target.UniqueKey] = fixup;
      return 0;
    }
    int GetParamIndex(Parameter p){
      if (p == null) return 0;
#if !MinimalReader
      ParameterBinding pb = p as ParameterBinding;
      if (pb != null) p = pb.BoundParameter;
#endif
      return this.paramIndex[p.UniqueKey];
    }
    int GetPropertyIndex(Property/*!*/ p) {
      return (int)this.propertyIndex[p.UniqueKey];
    }
    int GetSecurityAttributeParentCodedIndex(Node/*!*/ node) {
      switch(node.NodeType){
        case NodeType.InstanceInitializer:
        case NodeType.StaticInitializer:
        case NodeType.Method: return (this.GetMethodIndex((Method)node)<<2)|1;
        case NodeType.Class:
        case NodeType.Interface:
        case NodeType.DelegateNode:
        case NodeType.EnumNode:
        case NodeType.Struct: return (this.GetTypeDefIndex((TypeNode)node)<<2)|0;
        case NodeType.Assembly: return (1 << 2) | 2;
        default: Debug.Assert(false, "Unexpected security attribute parent"); return 0;
      }
    }
    int GetStandAloneSignatureIndex(BinaryWriter signatureWriter){
      this.standAloneSignatureEntries.Add(signatureWriter);
      return this.standAloneSignatureEntries.Count;
    }
    int GetStaticDataIndex(byte[] data, PESection targetSection){
      int result = 0;
      switch (targetSection){
        case PESection.SData:
          result = (int)this.sdataHeap.BaseStream.Position;
          this.sdataHeap.Write(data);
          break;
        case PESection.Text:
          result = (int)this.methodBodiesHeap.BaseStream.Position;
          this.methodBodiesHeap.Write(data);
          break;
        case PESection.TLS:
          result = (int)this.tlsHeap.BaseStream.Position;
          this.tlsHeap.Write(data);
          break;
      }
      return result;
    }
    int GetResourceDataIndex(byte[]/*!*/ data){
      int index = (int)this.resourceDataHeap.BaseStream.Position;
      this.resourceDataHeap.Write((int)data.Length);
      this.resourceDataHeap.Write(data);
      return index;
    }
    int GetStringIndex(string str) {
      if (str == null || str.Length == 0) return 0;
      Object index = this.stringHeapIndex[str];
      if (index == null){
        index = (int)this.stringHeap.BaseStream.Position;
        this.stringHeap.Write(str, true);
        this.stringHeapIndex[str] = index;
      }
      return (int)index;
    }
    int GetUserStringIndex(string/*!*/ str){
      Object index = this.userStringHeapIndex[str];
      if (index == null){
        index = (int)this.userStringHeap.BaseStream.Position;
        Ir2md.WriteCompressedInt(this.userStringHeap, str.Length*2+1);
        this.userStringHeap.Write(str.ToCharArray());
        this.userStringHeapIndex[str] = index;
        //Write out a trailing byte indicating if the string is really quite simple
        ulong stringKind = 0; //no funny business
        foreach (char ch in str){
          if (ch >= 0x7F) stringKind += 1;
          else
            switch((int)ch){
              case 0x1:
              case 0x2:
              case 0x3:
              case 0x4:
              case 0x5:
              case 0x6:
              case 0x7:
              case 0x8:
              case 0xE:
              case 0xF:
              case 0x10:
              case 0x11:
              case 0x12:
              case 0x13:
              case 0x14:
              case 0x15:
              case 0x16:
              case 0x17:
              case 0x18:
              case 0x19:
              case 0x1A:
              case 0x1B:
              case 0x1C:
              case 0x1D:
              case 0x1E:
              case 0x1F:
              case 0x27:
              case 0x2D:
                stringKind += 1;
                break;
              default:
                break;
            }
        }
        if (stringKind > 0) stringKind = 1;
        this.userStringHeap.Write((byte)stringKind);
      }
      return (int)index;
    }
    int GetTypeDefIndex(TypeNode/*!*/ type){
      Object index = this.typeDefIndex[type.UniqueKey];
      if (index == null){
        if (this.typeDefEntries == null) return 0;
        index = this.typeDefEntries.Count+1;
        this.typeDefEntries.Add(type);
        this.typeDefIndex[type.UniqueKey] = index;
        if (type.IsGeneric && type.Template == null)
          this.VisitGenericParameterList(type, type.ConsolidatedTemplateParameters);
      }
      return (int)index;
    }
    int GetTypeDefOrRefOrSpecEncoded(TypeNode type) {
      if (type == null) return 0;
      if (!this.UseGenerics) {
        ClassParameter cp = type as ClassParameter;
        if (cp != null) { Debug.Assert(!cp.IsGeneric); return this.GetTypeDefOrRefOrSpecEncoded(cp.BaseClass); } //REVIEW: why???
      }
      if (this.IsStructural(type)) return (this.GetTypeSpecIndex(type) << 2) | 2;
      if (type.DeclaringModule == this.module) return this.GetTypeDefIndex(type) << 2;
      return (this.GetTypeRefIndex(type) << 2)|1;
    }
    int GetTypeToken(TypeNode/*!*/ type) {
      if (this.IsStructural(type) && (!type.IsGeneric || (type.ConsolidatedTemplateArguments != null && type.ConsolidatedTemplateArguments.Count > 0)))
        return 0x1b000000 | this.GetTypeSpecIndex(type);
      if (type.IsGeneric){
        TypeNode foundType = type.GetTemplateInstance(type, type.TemplateParameters);
        Debug.Assert(foundType != type);
        return this.GetTypeToken(foundType);
      }
      if (type.DeclaringModule == this.module)
        return 0x02000000 | this.GetTypeDefIndex(type);
      else if (type.DeclaringModule != null)
        return 0x01000000 | this.GetTypeRefIndex(type);
      else if (type.typeCode == ElementType.ValueType || type.typeCode == ElementType.Class){
        type.DeclaringModule = this.module;
        return 0x02000000 | this.GetTypeDefIndex(type);
      }
      Debug.Assert(false);
      return 0;
    }
    int GetTypeDefToken(TypeNode/*!*/ type) {
      if (this.IsStructural(type) && (!type.IsGeneric || (type.Template != null && type.ConsolidatedTemplateArguments != null && type.ConsolidatedTemplateArguments.Count > 0)))
        return 0x1b000000 | this.GetTypeSpecIndex(type);
      if (type.DeclaringModule == this.module)
        return 0x02000000 | this.GetTypeDefIndex(type);
      else if (type.DeclaringModule != null)
        return 0x01000000 | this.GetTypeRefIndex(type);
      else if (type.typeCode == ElementType.ValueType || type.typeCode == ElementType.Class) {
        type.DeclaringModule = this.module;
        return 0x02000000 | this.GetTypeDefIndex(type);
      }
      Debug.Assert(false);
      return 0;
    }
    int GetTypeRefIndex(TypeNode/*!*/ type) {
      Object index = this.typeRefIndex[type.UniqueKey];
      if (index == null){
        index = this.typeRefEntries.Count+1;
        this.typeRefEntries.Add(type);
        this.typeRefIndex[type.UniqueKey] = index;
        Module module = type.DeclaringModule;
        AssemblyNode assembly = module as AssemblyNode;
        if (assembly != null)
          this.GetAssemblyRefIndex(assembly);
        else
          this.GetModuleRefIndex(module);
        if (type.DeclaringType != null)
          this.GetTypeRefIndex(type.DeclaringType);
      }
      return (int)index;
    }
    int GetTypeSpecIndex(TypeNode/*!*/ type) {
      int structuralKey = type.UniqueKey;
      int blobIndex = 0;
      if (type.Template != null){
        blobIndex = this.GetBlobIndex(type);
        structuralKey = ((type.Template.UniqueKey << 8)&int.MaxValue) + blobIndex;
      }
      Object index = this.typeSpecIndex[type.UniqueKey];
      if (index == null){
        if (type.Template != null){
          index = this.structuralTypeSpecIndexFor[structuralKey];
          if (index is int){
            TypeNode otherType = this.typeSpecEntries[((int)index)-1];
            if (otherType != null && otherType.Template == type.Template && blobIndex == this.GetBlobIndex(otherType))
              return (int)index;
          }
        }
        index = this.typeSpecEntries.Count+1;
        this.typeSpecEntries.Add(type);
        this.typeSpecIndex[type.UniqueKey] = index;
        if (type.Template != null)
          this.structuralTypeSpecIndexFor[structuralKey] = index;
        if (type.Template != null) {
          if (type.Template.DeclaringModule != this.module)
            this.GetTypeRefIndex(type.Template);
          TypeNodeList templArgs = type.ConsolidatedTemplateArguments;
          for (int i = 0, n = templArgs == null ? 0 : templArgs.Count; i < n; i++) {
            this.VisitReferencedType(templArgs[i]);
          }
        }else{
          TypeNodeList telems = type.StructuralElementTypes;
          for (int i = 0, n = telems == null ? 0 : telems.Count; i < n; i++)
            this.VisitReferencedType(telems[i]);
        }
      }
      return (int)index;
    }
    TrivialHashtable/*!*/ unspecializedFieldFor = new TrivialHashtable();
    Field/*!*/ GetUnspecializedField(Field/*!*/ field) {
      if (field == null || field.DeclaringType == null || !field.DeclaringType.IsGeneric) { Debug.Fail(""); return field; }
      Field unspecializedField = (Field)this.unspecializedFieldFor[field.UniqueKey];
      if (unspecializedField != null) return unspecializedField;
      TypeNode template = field.DeclaringType;
      if (template == null) { Debug.Assert(false); return field; }
      while (template.Template != null) template = template.Template;
      MemberList specializedMembers = field.DeclaringType.Members;
      MemberList unspecializedMembers = template.Members;
      for (int i = 0, n = specializedMembers.Count; i < n; i++){
        if (specializedMembers[i] != field) continue;
        unspecializedField = (Field)unspecializedMembers[i];
        if (unspecializedField == null) { Debug.Fail(""); unspecializedField = field; }
        this.unspecializedFieldFor[field.UniqueKey] = unspecializedField;
        this.VisitReferencedType(unspecializedField.DeclaringType);
        return unspecializedField;
      }
      Debug.Fail("");
      return field;
    }
    TrivialHashtable/*!*/ unspecializedMethodFor = new TrivialHashtable();
    Method/*!*/ GetUnspecializedMethod(Method/*!*/ method) {
      Debug.Assert(method != null && method.DeclaringType != null && method.DeclaringType.IsGeneric);
      Method unspecializedMethod = (Method)this.unspecializedMethodFor[method.UniqueKey];
      if (unspecializedMethod != null) return unspecializedMethod;
      TypeNode template = method.DeclaringType;
      if (template == null){Debug.Assert(false); return method;}
      while (template.Template != null) template = template.Template;
      MemberList specializedMembers = method.DeclaringType.Members;
      MemberList unspecializedMembers = template.Members;
      for (int i = 0, n = specializedMembers.Count; i < n; i++){
        if (specializedMembers[i] != method) continue;
        unspecializedMethod = unspecializedMembers[i] as Method;
        if (unspecializedMethod == null) break;
        goto FoundUnspecialized;
      }
      // try alternative
      unspecializedMethod = method;
      while (unspecializedMethod.Template != null) unspecializedMethod = unspecializedMethod.Template;

      if (unspecializedMethod.DeclaringType.Template == null) {
        goto FoundUnspecialized;
      }
      Debug.Assert(false);
      return method;
    FoundUnspecialized:
      this.unspecializedMethodFor[method.UniqueKey] = unspecializedMethod;
      template = unspecializedMethod.DeclaringType;
      while (template.Template != null) template = template.Template;
      this.VisitReferencedType(template);
      for (int j = 0, m = unspecializedMethod.TemplateParameters == null ? 0 : unspecializedMethod.TemplateParameters.Count; j < m; j++) {
        TypeNode p = unspecializedMethod.TemplateParameters[j];
        if (p == null) continue;
        this.typeParameterNumber[p.UniqueKey] = -(j + 1);
      }
      return unspecializedMethod;

    }
    internal void IncrementStackHeight(){
      this.stackHeight++;
      if (this.stackHeight > this.stackHeightMax) this.stackHeightMax = this.stackHeight;
    }
    void PopulateAssemblyTable()
      //^ requires this.assembly != null;
    {
      AssemblyNode assembly = this.assembly;
      AssemblyRow[] assemblyTable = this.writer.assemblyTable = new AssemblyRow[1];
      assemblyTable[0].HashAlgId = (int)AssemblyHashAlgorithm.SHA1;
      assemblyTable[0].Flags = (int)assembly.Flags;
      if (assembly.Version == null) assembly.Version = new Version(1,0,0,0);
      assemblyTable[0].MajorVersion = assembly.Version.Major;
      assemblyTable[0].MinorVersion = assembly.Version.Minor;
      assemblyTable[0].RevisionNumber = assembly.Version.Revision;
      assemblyTable[0].BuildNumber = assembly.Version.Build;
      if (assembly.PublicKeyOrToken != null && 0 < assembly.PublicKeyOrToken.Length)
        assemblyTable[0].PublicKey = this.GetBlobIndex(assembly.PublicKeyOrToken);
      if (assembly.Name != null)
        assemblyTable[0].Name = this.GetStringIndex(assembly.Name);
      else
        Debug.Assert(false, "Assembly must have a name");
      if (assembly.Culture != null && assembly.Culture.Length > 0)
        assemblyTable[0].Culture = this.GetStringIndex(assembly.Culture);
      this.writer.assemblyTable = assemblyTable;
    }
    void PopulateAssemblyRefTable(){
      AssemblyReferenceList arList = this.module.AssemblyReferences = this.assemblyRefEntries;
      if (arList == null) return;
      int n = arList.Count;
      AssemblyRefRow[] arRows = this.writer.assemblyRefTable = new AssemblyRefRow[n];
      for (int i = 0; i < n; i++){
        AssemblyReference ar = arList[i];
        if (ar.Version == null)
          Debug.Assert(false, "assembly reference without a version");
        else{
          arRows[i].MajorVersion = ar.Version.Major;
          arRows[i].MinorVersion = ar.Version.Minor;
          arRows[i].RevisionNumber = ar.Version.Revision;
          arRows[i].BuildNumber = ar.Version.Build;
          arRows[i].Flags = (int)ar.Flags;
        }
        if (ar.PublicKeyOrToken != null && 0 < ar.PublicKeyOrToken.Length)
          arRows[i].PublicKeyOrToken = this.GetBlobIndex(ar.PublicKeyOrToken);
        if (ar.Name == null) 
          Debug.Assert(false, "assembly reference without a name");
        else
          arRows[i].Name = this.GetStringIndex(ar.Name);
        if (ar.Culture != null && ar.Culture.Length > 0)
          arRows[i].Culture = this.GetStringIndex(ar.Culture);
        if (ar.HashValue != null)
          arRows[i].HashValue = this.GetBlobIndex(ar.HashValue);
      }
      //this.assemblyRefEntries = null;
    }
    void PopulateClassLayoutTable(){
      int n = this.classLayoutEntries.Count;
      if (n == 0) return;
      ClassLayoutRow[] clr = this.writer.classLayoutTable = new ClassLayoutRow[n];
      for (int i = 0; i < n; i++){
        TypeNode t = this.classLayoutEntries[i];
        clr[i].ClassSize = t.ClassSize;
        clr[i].PackingSize = t.PackingSize;
        clr[i].Parent = this.GetTypeDefIndex(t);
      }
      //this.classLayoutEntries = null;
    }
    void PopulateConstantTable(){
      int n = this.constantTableEntries.Count;
      if (n == 0) return;
      ConstantRow[] cr = this.writer.constantTable = new ConstantRow[n];
      for (int i = 0; i < n; i++){
        Parameter p = this.constantTableEntries[i] as Parameter;
        if (p != null){
          cr[i].Parent = (this.GetParamIndex(p) << 2) | 1;
          SetConstantTableEntryValueAndTypeCode(cr, i, (Literal)p.DefaultValue);
        } else {
          Field f = (Field)this.constantTableEntries[i];
          cr[i].Parent = (this.GetFieldIndex(f) << 2);
          SetConstantTableEntryValueAndTypeCode(cr, i, f.DefaultValue);
        }
        ConstantRow temp = cr[i];
        int parent = temp.Parent;
        for (int j = i-1; j >= 0; j--){
          if (cr[j].Parent > parent){
            cr[j+1] = cr[j];
            if (j == 0){
              cr[0] = temp;
              break;
            }
          }else{
            if (j < i-1) cr[j+1] = temp;
            break;
          }
        }
      }
      //TODO: more efficient sort
      //this.constantTableEntries = null;
    }

    private void SetConstantTableEntryValueAndTypeCode(ConstantRow[] cr, int i, Literal defaultValue)
    {
      cr[i].Value = this.GetBlobIndex(defaultValue);
      TypeNode t = defaultValue.Type;
      if (t.NodeType == NodeType.EnumNode) t = ((EnumNode)t).UnderlyingType;
      cr[i].Type = (int)t.typeCode;
      if (t is Reference || Literal.IsNullLiteral(defaultValue))
        cr[i].Type = (int)ElementType.Class;
    }
    void PopulateCustomAttributeTable(){
      if (this.customAttributeCount == 0) return;
      CustomAttributeRow[] table = this.writer.customAttributeTable = new CustomAttributeRow[this.customAttributeCount];
      int k = 0;
      int prevCodedIndex = 0;
      for (int i = 0, n = this.nodesWithCustomAttributes.Count; i < n; i++){
        AttributeList attrs = null;
        Node node = this.nodesWithCustomAttributes[i];
        int codedIndex = 0;
        switch(node.NodeType){
          case NodeType.Method:
          case NodeType.InstanceInitializer:
          case NodeType.StaticInitializer:
            Method m = (Method)node;
            codedIndex = this.GetMethodIndex(m)<<5; 
            attrs = m.Attributes;
            break;
          case NodeType.Field:
            Field f = (Field)node;
            codedIndex = (this.GetFieldIndex(f)<<5)|1;
            attrs = f.Attributes;
            break;
          case NodeType.Parameter:
            Parameter par = (Parameter)node;
            codedIndex = (this.GetParamIndex(par)<<5)|4;
            attrs = par.Attributes;
            break;
          case NodeType.Class:
          case NodeType.DelegateNode:
          case NodeType.EnumNode:
          case NodeType.Interface:
          case NodeType.Struct:
#if !MinimalReader
          case NodeType.TupleType:
          case NodeType.TypeAlias:
          case NodeType.TypeIntersection:
          case NodeType.TypeUnion:
#endif
            TypeNode t = (TypeNode)node;
            if (this.IsStructural(t) && (!t.IsGeneric || (t.Template != null && t.ConsolidatedTemplateArguments != null && t.ConsolidatedTemplateArguments.Count > 0)))
              codedIndex = (this.GetTypeSpecIndex(t)<<5)|13;
            else
              codedIndex = (this.GetTypeDefIndex(t)<<5)|3;
            attrs = t.Attributes;
            break;
          case NodeType.ClassParameter:
          case NodeType.TypeParameter:
            if (!this.UseGenerics) goto case NodeType.Class;
            t = (TypeNode)node;
            codedIndex = (this.GetGenericParamIndex(t)<<5)|19;
            attrs = t.Attributes;
            break;
          case NodeType.Property:
            Property p = (Property)node;
            codedIndex = (this.GetPropertyIndex(p)<<5)|9;
            attrs = p.Attributes;
            break;
          case NodeType.Event:
            Event e = (Event)node;
            codedIndex = (this.GetEventIndex(e)<<5)|10;
            attrs = e.Attributes;
            break;
          case NodeType.Module:
          case NodeType.Assembly:
            codedIndex =  (1 << 5) | (node.NodeType == NodeType.Module ? 7 : 14);
            attrs = ((Module)node).Attributes;
            break;
          default:
            Debug.Assert(false);
            break;
        }
        if (attrs == null) continue;
        if (UseGenerics) {
          Debug.Assert(codedIndex > prevCodedIndex);
        }
        prevCodedIndex = codedIndex;
        for (int j = 0, m = attrs.Count; j < m; j++){
          AttributeNode a = attrs[j];
          if (a == null) continue;
          table[k].Parent = codedIndex;
          Debug.Assert(a.Constructor is MemberBinding);
          Method cons = (Method)((MemberBinding)a.Constructor).BoundMember;
          if (cons.DeclaringType.DeclaringModule == this.module && !this.IsStructural(cons.DeclaringType))
            table[k].Constructor = (this.GetMethodIndex(cons) << 3) | 2;
          else
            table[k].Constructor = (this.GetMemberRefIndex(cons) << 3) | 3;
          table[k].Value = this.GetBlobIndex(a.Expressions, cons.Parameters);
          k++;
        }
      }
    }
    void PopulateDeclSecurityTable(){
      if (this.securityAttributeCount == 0) return;
      DeclSecurityRow[] table = this.writer.declSecurityTable = new DeclSecurityRow[this.securityAttributeCount];
      int k = 0;
      int prevCodedIndex = 0;
      for (int i = 0, n = this.nodesWithSecurityAttributes.Count; i < n; i++){
        SecurityAttributeList attrs = null;
        Node node = this.nodesWithSecurityAttributes[i];
        int codedIndex = 0;
        switch(node.NodeType){
          case NodeType.Method:
          case NodeType.InstanceInitializer:
          case NodeType.StaticInitializer:
            Method m = (Method)node;
            codedIndex = (this.GetMethodIndex(m)<<2)|1; 
            attrs = m.SecurityAttributes;
            break;
          case NodeType.Class:
          case NodeType.Interface:
          case NodeType.DelegateNode:
          case NodeType.EnumNode:
          case NodeType.Struct:
            TypeNode t = (TypeNode)node;
            codedIndex = (this.GetTypeDefIndex(t)<<2)|0;
            attrs = t.SecurityAttributes;
            break;
          case NodeType.Assembly:
            codedIndex =  (1 << 2)|2;
            attrs = ((AssemblyNode)node).SecurityAttributes;
            break;
          default:
            Debug.Assert(false);
            break;
        }
        if (attrs == null) continue;
        Debug.Assert(codedIndex > prevCodedIndex);
        prevCodedIndex = codedIndex;
        for (int j = 0, m = attrs.Count; j < m; j++){
          SecurityAttribute a = attrs[j];
          if (a == null) continue;
          this.VisitReferencedType(CoreSystemTypes.SecurityAction);
          table[k].Action = (int)a.Action;
          table[k].Parent = codedIndex;
          if (CoreSystemTypes.SystemAssembly.MetadataFormatMajorVersion == 1 && CoreSystemTypes.SystemAssembly.MetadataFormatMinorVersion < 1)
            table[k].PermissionSet = this.GetBlobIndex(a.SerializedPermissions);
          else {
            if (a.PermissionAttributes != null) {
              table[k].PermissionSet = this.GetBlobIndex(a.PermissionAttributes);
            } else {
              // Came across some assemblies that had a metadata version > 1.0, but still used
              // serialized security attributes. So might as well try to see if this is the case
              // if the PermissionAttributes are null.
              table[k].PermissionSet = this.GetBlobIndex(a.SerializedPermissions);
            }
          }
          k++;
        }
      }
    }
    void PopulateEventMapTable(){
      int n = this.eventMapEntries.Count;
      if (n == 0) return;
      EventMapRow[] emr = this.writer.eventMapTable = new EventMapRow[n];
      for (int i = 0; i < n; i++){
        Event e = this.eventMapEntries[i];
        emr[i].Parent = this.GetTypeDefIndex(e.DeclaringType);
        emr[i].EventList = this.GetEventIndex(e);
      }
      //this.eventMapEntries = null;
    }
    void PopulateEventTable(){
      int n = this.eventEntries.Count;
      if (n == 0) return;
      EventRow[] er = this.writer.eventTable = new EventRow[n];
      for (int i = 0; i < n; i++){
        Event e = this.eventEntries[i];
        if (e == null || e.Name == null) continue;
        er[i].Flags = (int)e.Flags;
        er[i].Name = this.GetStringIndex(e.Name.ToString());
        er[i].EventType = this.GetTypeDefOrRefOrSpecEncoded(e.HandlerType);
      }
      //this.eventEntries = null;
    }
    void PopulateExportedTypeTable(){
      if (this.assembly == null) return;
      TypeNodeList exportedTypes = this.assembly.ExportedTypes;
      int n = exportedTypes == null ? 0 : exportedTypes.Count;
      if (n == 0) return;
      ExportedTypeRow[] ett = this.writer.exportedTypeTable = new ExportedTypeRow[n];
      for (int i = 0; i < n; i++){
        TypeNode et = exportedTypes[i];
        if (et == null || et.Namespace == null || et.Name == null) continue;
        ett[i].TypeDefId = 0;
        ett[i].TypeNamespace = this.GetStringIndex(et.Namespace.ToString());
        ett[i].TypeName = this.GetStringIndex(et.Name.ToString());
        ett[i].Flags = (int)(et.Flags & TypeFlags.VisibilityMask);
        if (et.DeclaringType != null){
          for (int j = 0; j < i; j++){
            if (exportedTypes[j] == et.DeclaringType){
              ett[i].Implementation = ((j+1) << 2) | 2;
              break;
            }
          }
        } else if (et.DeclaringModule != this.module && et.DeclaringModule is AssemblyNode) {
          ett[i].Implementation = (this.GetAssemblyRefIndex((AssemblyNode)et.DeclaringModule) << 2) | 1;
          ett[i].Flags = (int)TypeFlags.Forwarder;
        } else
          ett[i].Implementation = (this.GetFileTableIndex(et.DeclaringModule) << 2) | 0;
      }
    }
    void PopulateFieldTable(){
      int n = this.fieldEntries.Count;
      if (n == 0) return;
      FieldRow[] fr = this.writer.fieldTable = new FieldRow[n];
      for (int i = 0; i < n; i++){
        Field f = this.fieldEntries[i];
        fr[i].Flags = (int)f.Flags;
        fr[i].Name = this.GetStringIndex(f.Name.Name); // we don't store prefixes in field names.
        fr[i].Signature = this.GetBlobIndex(f);
      }
      //this.fieldEntries = null;
    }
    void PopulateFieldLayoutTable(){
      int n = this.fieldLayoutEntries.Count;
      if (n == 0) return;
      FieldLayoutRow[] flr = this.writer.fieldLayoutTable = new FieldLayoutRow[n];
      for (int i = 0; i < n; i++){
        Field f = this.fieldLayoutEntries[i];
        flr[i].Field = this.GetFieldIndex(f);
        flr[i].Offset = f.Offset;
      }
      //this.fieldLayoutEntries = null;
    }
    void PopulateFieldRVATable(){
      int n = this.fieldRvaEntries.Count;
      if (n == 0) return;
      FieldRvaRow[] frr = this.writer.fieldRvaTable = new FieldRvaRow[n];
      for (int i = 0; i < n; i++){
        Field f = this.fieldRvaEntries[i];
        frr[i].Field = this.GetFieldIndex(f);
        if (f.InitialData != null)
          frr[i].RVA = this.GetStaticDataIndex(f.InitialData, f.Section); //Fixed up to be an RVA inside MetadataWriter.
        else
          frr[i].RVA = f.Offset;
        frr[i].TargetSection = f.Section;
      }
      //this.fieldRvaEntries = null;
    }
    void PopulateFileTable(){
      int n = this.fileTableEntries.Count;
      if (n == 0) return;
      bool readContents = false;
      FileRow[] ftr = this.writer.fileTable = new FileRow[n];
      for (int i = 0; i < n; i++){
        Module module = this.fileTableEntries[i];
        switch (module.Kind){
          case ModuleKindFlags.ConsoleApplication:
          case ModuleKindFlags.DynamicallyLinkedLibrary:
          case ModuleKindFlags.WindowsApplication:
            ftr[i].Flags = (int)FileFlags.ContainsMetaData;
            break;
          case ModuleKindFlags.ManifestResourceFile:
            readContents = true;
            ftr[i].Flags = (int)FileFlags.ContainsNoMetaData;
            break;
          case ModuleKindFlags.UnmanagedDynamicallyLinkedLibrary:
            ftr[i].Flags = (int)FileFlags.ContainsNoMetaData;
            break;
        }
        if (module.HashValue != null)
          ftr[i].HashValue = this.GetBlobIndex(module.HashValue);
        else
          ftr[i].HashValue = 0;
        ftr[i].Name = this.GetStringIndex(module.Name);
        if (readContents){
          try{
            FileStream fs = File.OpenRead(module.Location);
            long size = fs.Length;
            byte[] buffer = new byte[size];
            fs.Read(buffer, 0, (int)size);
            System.Security.Cryptography.SHA1 sha1 = new System.Security.Cryptography.SHA1CryptoServiceProvider();
            byte[] hash = sha1.ComputeHash(buffer);
            ftr[i].HashValue = this.GetBlobIndex(hash);
          }catch{}
        }
      }
      //this.fileTableEntries = null;
    }
    void PopulateGuidTable(){
      int n = this.guidEntries.Count;
      Guid[] guids = this.writer.GuidHeap = new Guid[n];
      for (int i = 0; i < n; i++)
        guids[i] = (Guid)this.guidEntries[i];
      //this.guidEntries = null;
    }
    void PopulateGenericParamTable(){
      int n = this.genericParamEntries.Count;
      if (n == 0) return;
      GenericParamRow[] gpr = this.writer.genericParamTable = new GenericParamRow[n];
      Member lastMember = null;
      int number = 0;
      for (int i = 0; i < n; i++){
        Member m = this.genericParamEntries[i];
        TypeNode paramType = this.genericParameters[i];
        if (paramType == null || paramType.Name == null) continue;
        Method meth = m as Method;
        TypeNode type = m as TypeNode;
        if (m != lastMember) number = 0;
        gpr[i].GenericParameter = paramType;
        gpr[i].Number = number++;
        if (type != null){
          gpr[i].Name = this.GetStringIndex(paramType.Name.ToString());
          gpr[i].Owner = (this.GetTypeDefIndex(type) << 1)|0;
        }else{
          //^ assert meth != null;
          gpr[i].Name = this.GetStringIndex(paramType.Name.ToString());
          gpr[i].Owner = (this.GetMethodIndex(meth) << 1)|1;
        }
        ITypeParameter tp = paramType as ITypeParameter;
        if (tp != null)
          gpr[i].Flags = (int)tp.TypeParameterFlags;
        else{
          Debug.Assert(false);
          gpr[i].Flags = 0;
        }
        lastMember = m;
        GenericParamRow temp = gpr[i];
        int owner = temp.Owner;
        for (int j = i-1; j >= 0; j--){
          if (gpr[j].Owner > owner){
            gpr[j+1] = gpr[j];
            if (j == 0){
              gpr[0] = temp;
              break;
            }
          }else{
            if (j < i-1) gpr[j+1] = temp;
            break;
          }
        }
      }
      for (int i = 0; i < n; i++){
        Member genPar = gpr[i].GenericParameter;
        if (genPar == null) continue;
        this.genericParamIndex[genPar.UniqueKey] = i+1;
      }
      for (int i = 0; i < n; i++) {
        Member genPar = gpr[i].GenericParameter;
        if (genPar == null) continue;
        this.VisitAttributeList(genPar.Attributes, genPar);
      }
      //this.genericParamEntries = null;
      //this.genericParameters = null;
    }
    void PopulateGenericParamConstraintTable(){
      int n = this.genericParamConstraintEntries.Count;
      if (n == 0) return;
      GenericParamConstraintRow[] gpcr = this.writer.genericParamConstraintTable = new GenericParamConstraintRow[n];
      TypeNode lastParameter = null;
      int paramIndex = 0;
      int constraintIndex = 0;
#if !CodeContracts
      int indexOffset = 0;
#endif
      for (int i = 0; i < n; i++){
        TypeNode t = this.genericParamConstraintEntries[i];
        if (t != lastParameter){
          paramIndex = this.GetGenericParamIndex(t);
          constraintIndex = 0; 
#if !CodeContracts
          indexOffset = 0;
#endif
        }
        gpcr[i].Param = paramIndex;
        TypeNode constraint;
#if CodeContracts
        constraint = t.StructuralElementTypes[constraintIndex];
#else
        if (constraintIndex == 0 && t.BaseType != null && t.BaseType != CoreSystemTypes.Object){
          constraint = t.BaseType; indexOffset = 1;
        }else
          constraint = t.Interfaces[constraintIndex-indexOffset];
#endif
        gpcr[i].Constraint = this.GetTypeDefOrRefOrSpecEncoded(constraint);
        lastParameter = t;
        constraintIndex++;
        GenericParamConstraintRow temp = gpcr[i];
        int param = temp.Param;
        for (int j = i - 1; j >= 0; j--) {
          if (gpcr[j].Param > param) {
            gpcr[j + 1] = gpcr[j];
            if (j == 0) {
              gpcr[0] = temp;
              break;
            }
          } else {
            if (j < i - 1) gpcr[j + 1] = temp;
            break;
          }
        }
      }
      //this.genericParamConstraintEntries = null;
    }
    void PopulateImplMapTable(){
      int n = this.implMapEntries.Count;
      if (n == 0) return;
      ImplMapRow[] imr = this.writer.implMapTable = new ImplMapRow[n];
      for (int i = 0; i < n; i++){
        Method m = this.implMapEntries[i];
        imr[i].ImportName = this.GetStringIndex(m.PInvokeImportName);
        imr[i].ImportScope = this.GetModuleRefIndex(m.PInvokeModule);
        imr[i].MappingFlags = (int)m.PInvokeFlags;
        imr[i].MemberForwarded = (this.GetMethodIndex(m) << 1)|1;
      }
      //this.implMapEntries = null;
    }
    void PopulateInterfaceImplTable(){
      int n = this.interfaceEntries.Count;
      if (n == 0) return;
      InterfaceImplRow[] iir = this.writer.interfaceImplTable = new InterfaceImplRow[n];
      TypeNode prevT = null;
      for (int i = 0, j = 0; i < n; i++){
        TypeNode t = this.interfaceEntries[i];
        if (t == prevT)
          j++;
        else{
          j = 0;
          prevT = t;
        }
        int ti = iir[i].Class = this.GetTypeDefIndex(t);
        Interface iface = null;
#if ExtendedRuntime
        if (t is ITypeParameter){
          int numIfaces = t.Interfaces == null ? 0 : t.Interfaces.Count;
          if (j == numIfaces)
            iface = SystemTypes.ITemplateParameter;
          else
            iface = t.Interfaces[j];
        }else
#endif
          iface = t.Interfaces[j];
        if (iface == null){i--; continue;}
        int ii = iir[i].Interface = this.GetTypeDefOrRefOrSpecEncoded(iface);
        for (int k = 0; k < i; k++){ //REVIEW: is a more efficient sort worthwhile?
          if (iir[k].Class > ti){
            for (int kk = i; kk > k; kk--){
              iir[kk].Class = iir[kk-1].Class;
              iir[kk].Interface = iir[kk-1].Interface;
            }
            iir[k].Class = ti;
            iir[k].Interface = ii;
            break;
          }
        }
      }
      //this.interfaceEntries = null;
    }
    void PopulateManifestResourceTable(){
      ResourceList resources = this.module.Resources;
      int n = resources == null ? 0 : resources.Count;
      if (n == 0) return;
      ManifestResourceRow[] mresources = this.writer.manifestResourceTable = new ManifestResourceRow[n];
      for (int i = 0; i < n; i++){
        Resource r = resources[i];
        mresources[i].Flags = r.IsPublic ? 1 : 2;
        mresources[i].Name = this.GetStringIndex(r.Name);
        if (r.Data != null)
          mresources[i].Offset = this.GetResourceDataIndex(r.Data);
        else if (r.DefiningModule is AssemblyNode)
          mresources[i].Implementation = (this.GetAssemblyRefIndex((AssemblyNode)r.DefiningModule)<<2)|1;
        else
          mresources[i].Implementation = (this.GetFileTableIndex(r.DefiningModule)<<2)|0;
      }
    }
    void PopulateMarshalTable(){
      int n = this.marshalEntries.Count;
      if (n == 0) return;
      FieldMarshalRow[] fmr = this.writer.fieldMarshalTable = new FieldMarshalRow[n];
      for (int i = 0; i < n; i++){
        MarshallingInformation mi;
        Field f = this.marshalEntries[i] as Field;
        if (f != null){
          fmr[i].Parent = (this.GetFieldIndex(f)<<1)|0;
          mi = f.MarshallingInformation;
        }else{
          Parameter p = (Parameter)this.marshalEntries[i];
          fmr[i].Parent = (this.GetParamIndex(p)<<1)|1;
          mi = p.MarshallingInformation;
        }
        int nt = fmr[i].NativeType = this.GetBlobIndex(mi);
        int pi = fmr[i].Parent;
        for (int k = 0; k < i; k++){ //REVIEW: is a more efficient sort worthwhile?
          if (fmr[k].Parent > pi){
            for (int kk = i; kk > k; kk--){
              fmr[kk].Parent = fmr[kk-1].Parent;
              fmr[kk].NativeType = fmr[kk-1].NativeType;
            }
            fmr[k].Parent = pi;
            fmr[k].NativeType = nt;
            break;
          }
        }
      }
      //this.marshalEntries = null;
    }
    void PopulateMemberRefTable(){
      int n = this.memberRefEntries.Count;
      if (n == 0) return;
      MemberRefRow[] mr = this.writer.memberRefTable = new MemberRefRow[n];
      for (int i = 0; i < n; i++){
        Member member = this.memberRefEntries[i];
        if (member == null || member.Name == null) continue;
        mr[i].Name = this.GetStringIndex(member.Name.ToString());
        Field f = member as Field;
        if (f != null)
          mr[i].Signature = this.GetBlobIndex(f);
        else{
          FunctionPointer fp = member as FunctionPointer;
          if (fp != null){
            mr[i].Signature = this.GetBlobIndex(fp);
            if (fp is VarargMethodCallSignature){
              Method m = ((VarargMethodCallSignature)member).method;
              if (m != null && m.DeclaringType.DeclaringModule == this.module && !this.IsStructural(m.DeclaringType)){
                mr[i].Class = (this.GetMethodIndex(m) << 3) | 3;
                continue;
              }
            }
          }else{
            Method m = (Method)member;
            if (m.IsGeneric && m.Template != null) m = this.GetUnspecializedMethod(m);
            mr[i].Signature = this.GetBlobIndex(m, false);
            if (m.DeclaringType.DeclaringModule == this.module && !this.IsStructural(m.DeclaringType) && !m.IsGeneric){
              mr[i].Class = (this.GetMethodIndex(m) << 3) | 3;
              continue;
            }
            //TODO: if the declaring type is the special global members type of another module, set class to a module ref
          }
        }
        int j = mr[i].Class = this.GetMemberRefParentEncoded(member.DeclaringType);
        if ((j & 0x3) == 2) mr[i].Class = (j & ~0x3) | 4;
      }
      //this.memberRefEntries = null;
    }
    void PopulateMethodTable(){
      int n = this.methodEntries.Count;
      if (n == 0) return;
      MethodRow[] mr = this.writer.methodTable = new MethodRow[n];
      for (int i = 0; i < n; i++){
        Method m = this.methodEntries[i];
        if (m == null || m.Name == null) continue;
        if (m.IsAbstract || m.Body == null || m.Body.Statements == null || m.Body.Statements.Count == 0)
          mr[i].RVA = -1;
        else
          mr[i].RVA = this.GetMethodBodiesHeapIndex(m); //Fixed up to be an RVA inside MetadataWriter.
        mr[i].Flags = (int)m.Flags;
        mr[i].ImplFlags = (int)m.ImplFlags;
        mr[i].Name = this.GetStringIndex(m.Name.ToString());
        mr[i].Signature = this.GetBlobIndex(m, false);
        if (m.ReturnTypeMarshallingInformation != null || (m.ReturnAttributes != null && m.ReturnAttributes.Count > 0))
          mr[i].ParamList = this.paramIndex[m.UniqueKey];
        else{
          ParameterList pars = m.Parameters;
          if (pars != null && pars.Count > 0){
            Debug.Assert(pars[0] != null && pars[0].DeclaringMethod == m);
            mr[i].ParamList = this.GetParamIndex(pars[0]);
          }else
            mr[i].ParamList = 0;
        }
      }
      //this.methodEntries = null;
    }
    void PopulateMethodImplTable(){
      int n = this.methodImplEntries.Count;
      if (n == 0) return;
      MethodImplRow[] mir = this.writer.methodImplTable = new MethodImplRow[n];
      int j = 0;
      Method lastMethod = null;
      for (int i = 0; i < n; i++){
        Method m = this.methodImplEntries[i];
        if (lastMethod != m) j = 0;
        mir[i].Class = this.GetTypeDefIndex(m.DeclaringType);
        if (m.DeclaringType.DeclaringModule == this.module)
          mir[i].MethodBody =  this.GetMethodIndex(m) << 1;
        else
          mir[i].MethodBody = (this.GetMemberRefIndex(m) << 1)|0x1;
        Method im = m.ImplementedInterfaceMethods[j++];
        while (im == null) im = m.ImplementedInterfaceMethods[j++];
        mir[i].MethodDeclaration = this.GetMethodDefOrRefEncoded(im);
        lastMethod = m;
      }
      //this.methodImplEntries = null;
    }
    void PopulateMethodSpecTable(){
      int n = this.methodSpecEntries.Count;
      if (n == 0) return;
      MethodSpecRow[] msr = this.writer.methodSpecTable = new MethodSpecRow[n];
      for (int i = 0; i < n; i++){
        Method m = this.methodSpecEntries[i];
        msr[i].Method = this.GetMethodDefOrRefEncoded(m.Template);
        msr[i].Instantiation = this.GetBlobIndex(m, true);
        //TODO: sort this and eliminate duplicates.
        //Duplicates can arise when methods are instantiated with method parameters from different methods.
        //TODO: perhaps this duplication should be prevented by Method.GetTemplateInstance?
      }
      //this.methodEntries = null;
    }
    void PopulateMethodSemanticsTable(){
      int n = this.methodSemanticsEntries.Count;
      if (n == 0) return;
      MethodSemanticsRow[] msr = this.writer.methodSemanticsTable = new MethodSemanticsRow[n];
      Member previousOwner = null;
      int index = -1;
      for (int i = 0; i < n; i++){
        Member owner = this.methodSemanticsEntries[i];
        Property ownerProperty = owner as Property;
        if (ownerProperty != null){
          msr[i].Association = (this.GetPropertyIndex(ownerProperty) << 1)|1;
          if (owner != previousOwner){
            previousOwner = owner;
            index = -1;
            if (ownerProperty.Getter != null) {
              msr[i].Method = this.GetMethodIndex(ownerProperty.Getter);
              msr[i].Semantics = 0x0002;
              continue;
            }
          }
          if (index == -1){
            index = 0;
            if (ownerProperty.Setter != null) {
              msr[i].Method = this.GetMethodIndex(ownerProperty.Setter);
              msr[i].Semantics = 0x0001;
              continue;
            }
          }
          msr[i].Method = this.GetMethodIndex(ownerProperty.OtherMethods[index]);
          msr[i].Semantics = 0x0004;
          index++;
          continue;
        }
        Event ownerEvent = owner as Event;
        if (ownerEvent == null) { Debug.Fail(""); continue; }
        msr[i].Association = this.GetEventIndex(ownerEvent)<<1;
        if (owner != previousOwner){
          previousOwner = owner;
          index = -2;
          if (ownerEvent.HandlerAdder != null){
            msr[i].Method = this.GetMethodIndex(ownerEvent.HandlerAdder);
            msr[i].Semantics = 0x0008;
            continue;
          }
        }
        if (index == -2){
          index = -1;
          if (ownerEvent.HandlerRemover != null){
            msr[i].Method = this.GetMethodIndex(ownerEvent.HandlerRemover);
            msr[i].Semantics = 0x0010;
            continue;
          }
        }
        if (index == -1){
          index = 0;
          if (ownerEvent.HandlerCaller != null){
            msr[i].Method = this.GetMethodIndex(ownerEvent.HandlerCaller);
            msr[i].Semantics = 0x0020;
            continue;
          }
        }
        msr[i].Method = this.GetMethodIndex(ownerEvent.OtherMethods[i]);
        msr[i].Semantics = 0x0004;
        index++;
        continue;
      }
      System.Array.Sort(msr, new MethodSemanticsRowComparer());
      //this.methodSemanticsEntries = null;
    }
    class MethodSemanticsRowComparer : IComparer{
      int IComparer.Compare(object x, object y) {
        MethodSemanticsRow xr = (MethodSemanticsRow)x;
        MethodSemanticsRow yr = (MethodSemanticsRow)y;
        int result = xr.Association - yr.Association;
        if (result == 0) result = xr.Method - yr.Method;
        return result;
      }
    }
    void PopulateModuleTable(){
      ModuleRow[] mr = this.writer.moduleTable = new ModuleRow[1];
      string name = this.module.Name;
      if (this.assembly != null){
        if (this.assembly.ModuleName != null)
          name = this.assembly.ModuleName;
        else{
          string extension = ".exe";
          if (this.module.Kind == ModuleKindFlags.DynamicallyLinkedLibrary) extension = ".dll";
          name = name + extension;
        }
      }
      mr[0].Name = this.GetStringIndex(name);
      mr[0].Mvid = this.GetGuidIndex(Guid.NewGuid());
    }
    void PopulateModuleRefTable(){
      int n = this.moduleRefEntries.Count;
      if (n == 0) return;
      ModuleRefRow[] mrr = this.writer.moduleRefTable = new ModuleRefRow[n];
      for (int i = 0; i < n; i++){
        ModuleReference moduleRef = this.moduleRefEntries[i];
        mrr[i].Name = this.GetStringIndex(moduleRef.Name);
      }
      //this.moduleRefEntries = null;
    }
    void PopulateNestedClassTable(){
      int n = this.nestedClassEntries.Count;
      if (n == 0) return;
      NestedClassRow[] ncr = this.writer.nestedClassTable = new NestedClassRow[n];
      for (int i = 0; i < n; i++){
        TypeNode nt = this.nestedClassEntries[i];
        ncr[i].NestedClass = this.GetTypeDefIndex(nt);
        ncr[i].EnclosingClass = this.GetTypeDefIndex(nt.DeclaringType);
      }
      //this.nestedClassEntries = null;
    }
    void PopulateParamTable(){
      int n = this.paramEntries.Count;
      if (n == 0) return;
      ParamRow[] pr = this.writer.paramTable = new ParamRow[n];
      for (int i = 0; i < n; i++){
        Parameter p = this.paramEntries[i];
        if (p == null) continue;
        bool paramShouldHaveNoName = (p.Flags & ParameterFlags.ParameterNameMissing) != 0;
        p.Flags &= ~ParameterFlags.ParameterNameMissing;
        pr[i].Flags = (int)p.Flags;
        pr[i].Sequence = p.ParameterListIndex+1;
        pr[i].Name = ((paramShouldHaveNoName || p.Name == null) ? 0 : this.GetStringIndex(p.Name.ToString()));
      }
      //this.paramEntries = null;
    }
    void PopulatePropertyTable(){
      int n = this.propertyEntries.Count;
      if (n == 0) return;
      PropertyRow[] pr = this.writer.propertyTable = new PropertyRow[n];
      for (int i = 0; i < n; i++){
        Property p = this.propertyEntries[i];
        if (p == null || p.Name == null) continue;
        pr[i].Flags = (int)p.Flags;
        pr[i].Name = this.GetStringIndex(p.Name.ToString());
        pr[i].Signature = this.GetBlobIndex(p);
      }
      //this.propertyEntries = null;
    }
    void PopulatePropertyMapTable(){
      int n = this.propertyMapEntries.Count;
      if (n == 0) return;
      PropertyMapRow[] pmr = this.writer.propertyMapTable = new PropertyMapRow[n];
      for (int i = 0; i < n; i++){
        Property p = this.propertyMapEntries[i];
        pmr[i].Parent = this.GetTypeDefIndex(p.DeclaringType);
        pmr[i].PropertyList = this.GetPropertyIndex(p);
      }
      //this.propertyMapEntries = null;
    }
    void PopulateStandAloneSigTable(){
      int n = this.standAloneSignatureEntries.Count;
      if (n == 0) return;
      StandAloneSigRow[] sasr = this.writer.standAloneSigTable = new StandAloneSigRow[n];
      for (int i = 0; i < n; i++){
        BinaryWriter sigWriter = (BinaryWriter)this.standAloneSignatureEntries[i];
        sasr[i].Signature = this.GetBlobIndex(((MemoryStream)sigWriter.BaseStream).ToArray());
      }
    }
    void PopulateTypeDefTable(){
      int n = this.typeDefEntries.Count;
      if (n == 0) return;
      TypeDefRow[] tdr = this.writer.typeDefTable = new TypeDefRow[n];
      for (int i = 0; i < n; i++){
        TypeNode t = this.typeDefEntries[i];
        if (t == null) continue;
        tdr[i].Flags = (int)t.Flags;
        tdr[i].Name = this.GetStringIndex(t.Name == null ? "" : t.Name.ToString());
#if DEBUG
        if (t.IsGeneric)
        {
          var tcount = t.TemplateParameters == null ? 0 : t.TemplateParameters.Count;
          if (tcount > 0)
          {
            var quoteIndex = t.Name.Name.LastIndexOf(TargetPlatform.GenericTypeNamesMangleChar);
            Debug.Assert(quoteIndex > 0);
            int tcountInName;
            Debug.Assert(Int32.TryParse(t.Name.Name.Substring(quoteIndex + 1), out tcountInName));
            Debug.Assert(tcountInName == tcount);
          }
        }
#endif
        tdr[i].Namespace = t.Namespace == null ? 0 : this.GetStringIndex(t.Namespace == null ? "" : t.Namespace.ToString());
        tdr[i].Extends = this.GetTypeDefOrRefOrSpecEncoded(t.BaseType);
        MemberList members = t.Members;
        int m = members.Count;
        for (int j = 0; j < m; j++){
          Member mem = members[j];
          if (mem == null) continue;
          if (mem.NodeType == NodeType.Field){
            tdr[i].FieldList = this.GetFieldIndex((Field)mem);
            break;
          }
        }
        for (int j = 0; j < m; j++){
          Member mem = members[j];
          if (mem == null) continue;
          switch(mem.NodeType){
            case NodeType.Method:
            case NodeType.InstanceInitializer:
            case NodeType.StaticInitializer:
              tdr[i].MethodList = this.GetMethodIndex((Method)mem);
              goto done;
          }
        }
      done: continue;
      }
      //this.typeDefEntries = null;
    }
    void PopulateTypeRefTable(){
      int n = this.typeRefEntries.Count;
      if (n == 0) return;
      TypeRefRow[] trr = this.writer.typeRefTable = new TypeRefRow[n];
      for (int i = 0; i < n; i++){
        TypeNode t = this.typeRefEntries[i];
        if (t == null || t.Name == null || t.Namespace == null) continue;
        trr[i].Name = this.GetStringIndex(t.Name.ToString());
        trr[i].Namespace = this.GetStringIndex(t.Namespace.ToString());
        if (t.DeclaringType == null)
          if (t.DeclaringModule is AssemblyNode)
            trr[i].ResolutionScope = (this.GetAssemblyRefIndex((AssemblyNode)t.DeclaringModule) << 2) | 2;
          else
            trr[i].ResolutionScope = (this.GetModuleRefIndex(t.DeclaringModule) << 2) | 1;
        else
          trr[i].ResolutionScope = (this.GetTypeRefIndex(t.DeclaringType) << 2) | 3;
      }
      //this.typeRefEntries = null;
    }
    void PopulateTypeSpecTable(){
      int n = this.typeSpecEntries.Count;
      if (n == 0) return;
      TypeSpecRow[] tsr = this.writer.typeSpecTable = new TypeSpecRow[n];
      for (int i = 0; i < n; i++){
        TypeNode t = this.typeSpecEntries[i];
        tsr[i].Signature = this.GetBlobIndex(t);
        //TODO: eliminate duplicates
      }
      //this.typeSpecEntries = null;
    }
    void Visit(Node node){
      if (node == null) return;
      switch (node.NodeType){
        case NodeType.AddressDereference:
          this.VisitAddressDereference((AddressDereference)node); return;
        case NodeType.Arglist :
          this.VisitExpression((Expression)node); return;
        case NodeType.AssignmentStatement : 
          this.VisitAssignmentStatement((AssignmentStatement)node); return;
#if !MinimalReader && !CodeContracts
        case NodeType.Base :
          this.VisitBase((Base)node); return;
#endif
        case NodeType.Block : 
          this.VisitBlock((Block)node); return;
#if !MinimalReader
        case NodeType.BlockExpression :
          this.VisitBlockExpression((BlockExpression)node); return;
#endif
        case NodeType.Branch :
          this.VisitBranch((Branch)node); return;
        case NodeType.DebugBreak :
          this.VisitStatement((Statement)node); return;
        case NodeType.Call :
        case NodeType.Calli :
        case NodeType.Callvirt :
        case NodeType.Jmp :
#if !MinimalReader
        case NodeType.MethodCall :
#endif
          this.VisitMethodCall((MethodCall)node); return;
        case NodeType.Class :
        case NodeType.ClassParameter:
          this.VisitClass((Class)node); return;
        case NodeType.Construct :
          this.VisitConstruct((Construct)node); return;
        case NodeType.ConstructArray :
          this.VisitConstructArray((ConstructArray)node); return;
        case NodeType.DelegateNode :
          this.VisitDelegateNode((DelegateNode)node); return;
        case NodeType.Dup :
          this.VisitExpression((Expression)node); return;
        case NodeType.EndFilter :
          this.VisitEndFilter((EndFilter)node); return;
        case NodeType.EndFinally:
          this.VisitStatement((Statement)node); return;
        case NodeType.EnumNode :
          this.VisitEnumNode((EnumNode)node); return;
        case NodeType.Event: 
          this.VisitEvent((Event)node); return;
        case NodeType.ExpressionStatement :
          this.VisitExpressionStatement((ExpressionStatement)node); return;
        case NodeType.Field :
          this.VisitField((Field)node); return;
        case NodeType.Indexer :
          this.VisitIndexer((Indexer)node); return;
        case NodeType.InstanceInitializer :
        case NodeType.StaticInitializer :
        case NodeType.Method: 
          this.VisitMethod((Method)node); return;
        case NodeType.TypeParameter:
        case NodeType.Interface :
          this.VisitInterface((Interface)node); return;
        case NodeType.Literal:
          this.VisitLiteral((Literal)node); return;
        case NodeType.Local :
          this.VisitLocal((Local)node); return;
#if !MinimalReader && !CodeContracts
        case NodeType.LocalDeclarationsStatement:
          this.VisitLocalDeclarationsStatement((LocalDeclarationsStatement)node); return;
#endif
        case NodeType.MemberBinding :
          this.VisitMemberBinding((MemberBinding)node); return;
        case NodeType.Nop :
          this.VisitStatement((Statement)node); return;
        case NodeType.Parameter :
          this.VisitParameter((Parameter)node); return;
        case NodeType.Pop :
          this.VisitExpression((Expression)node); return;
        case NodeType.Property: 
          this.VisitProperty((Property)node); return;
        case NodeType.Rethrow :
        case NodeType.Throw :
          this.VisitThrow((Throw)node); return;
        case NodeType.Return:
          this.VisitReturn((Return)node); return;
        case NodeType.Struct :
#if !MinimalReader
        case NodeType.TypeAlias :
        case NodeType.TypeIntersection :
        case NodeType.TypeUnion:
        case NodeType.TupleType:
#endif
          this.VisitStruct((Struct)node); return;
#if !MinimalReader
        case NodeType.SwitchCaseBottom:
          return;
#endif
        case NodeType.SwitchInstruction :
          this.VisitSwitchInstruction((SwitchInstruction)node); return;
        case NodeType.This :
          this.VisitThis((This)node); return;

        case NodeType.Cpblk :
        case NodeType.Initblk :
          this.VisitTernaryExpression((TernaryExpression)node); return;

        case NodeType.Add : 
        case NodeType.Add_Ovf : 
        case NodeType.Add_Ovf_Un : 
        case NodeType.And : 
        case NodeType.Box :
        case NodeType.Castclass : 
        case NodeType.Ceq : 
        case NodeType.Cgt : 
        case NodeType.Cgt_Un : 
        case NodeType.Clt : 
        case NodeType.Clt_Un : 
        case NodeType.Div : 
        case NodeType.Div_Un : 
        case NodeType.Eq : 
        case NodeType.Ge : 
        case NodeType.Gt : 
#if !MinimalReader
        case NodeType.Is : 
#endif
        case NodeType.Isinst : 
        case NodeType.Ldvirtftn :
        case NodeType.Le : 
        case NodeType.Lt : 
        case NodeType.Mkrefany :
        case NodeType.Mul : 
        case NodeType.Mul_Ovf : 
        case NodeType.Mul_Ovf_Un : 
        case NodeType.Ne : 
        case NodeType.Or : 
        case NodeType.Refanyval :
        case NodeType.Rem : 
        case NodeType.Rem_Un : 
        case NodeType.Shl : 
        case NodeType.Shr : 
        case NodeType.Shr_Un : 
        case NodeType.Sub : 
        case NodeType.Sub_Ovf : 
        case NodeType.Sub_Ovf_Un : 
        case NodeType.Unbox : 
        case NodeType.UnboxAny :
        case NodeType.Xor : 
          this.VisitBinaryExpression((BinaryExpression)node); return;

        
        case NodeType.AddressOf:
#if !MinimalReader        
        case NodeType.OutAddress:
        case NodeType.RefAddress:
#endif
        case NodeType.ReadOnlyAddressOf:
          this.VisitAddressOf((UnaryExpression)node); return;
        case NodeType.Ckfinite :
        case NodeType.Conv_I :
        case NodeType.Conv_I1 :
        case NodeType.Conv_I2 :
        case NodeType.Conv_I4 :
        case NodeType.Conv_I8 :
        case NodeType.Conv_Ovf_I :
        case NodeType.Conv_Ovf_I1 :
        case NodeType.Conv_Ovf_I1_Un :
        case NodeType.Conv_Ovf_I2 :
        case NodeType.Conv_Ovf_I2_Un :
        case NodeType.Conv_Ovf_I4 :
        case NodeType.Conv_Ovf_I4_Un :
        case NodeType.Conv_Ovf_I8 :
        case NodeType.Conv_Ovf_I8_Un :
        case NodeType.Conv_Ovf_I_Un :
        case NodeType.Conv_Ovf_U :
        case NodeType.Conv_Ovf_U1 :
        case NodeType.Conv_Ovf_U1_Un :
        case NodeType.Conv_Ovf_U2 :
        case NodeType.Conv_Ovf_U2_Un :
        case NodeType.Conv_Ovf_U4 :
        case NodeType.Conv_Ovf_U4_Un :
        case NodeType.Conv_Ovf_U8 :
        case NodeType.Conv_Ovf_U8_Un :
        case NodeType.Conv_Ovf_U_Un :
        case NodeType.Conv_R4 :
        case NodeType.Conv_R8 :
        case NodeType.Conv_R_Un :
        case NodeType.Conv_U :
        case NodeType.Conv_U1 :
        case NodeType.Conv_U2 :
        case NodeType.Conv_U4 :
        case NodeType.Conv_U8 :
        case NodeType.Ldftn :
        case NodeType.Ldlen :
        case NodeType.Ldtoken :
        case NodeType.Localloc :
        case NodeType.Neg :
        case NodeType.Not :
        case NodeType.Refanytype :
        case NodeType.Sizeof :
          this.VisitUnaryExpression((UnaryExpression)node); return;

        default:
          // handle type extensions with new NodeType's, that are emitted as ordinary structs and classes
          Class cl = node as Class;
          if (cl != null){
            this.VisitClass(cl); return;
          }
          Struct st = node as Struct;
          if (st != null){
            this.VisitStruct(st); return;
          }
          Debug.Assert(false, "invalid node: " + node.NodeType.ToString());
          return;
      }
    }
    void VisitAddressDereference(AddressDereference/*!*/ adr) {
      this.Visit(adr.Address);
      if (adr.Alignment > 0){
        this.methodBodyHeap.Write((byte)0xfe);
        this.methodBodyHeap.Write((byte)0x12);
        this.methodBodyHeap.Write((byte)adr.Alignment);
      }
      if (adr.Volatile){
        this.methodBodyHeap.Write((byte)0xfe);
        this.methodBodyHeap.Write((byte)0x13);
      }
      switch(adr.Type.typeCode){
        case ElementType.Int8:   this.methodBodyHeap.Write((byte)0x46); return;
        case ElementType.UInt8:  this.methodBodyHeap.Write((byte)0x47); return;
        case ElementType.Int16:  this.methodBodyHeap.Write((byte)0x48); return;
        case ElementType.Char:
        case ElementType.UInt16: this.methodBodyHeap.Write((byte)0x49); return;
        case ElementType.Int32:  this.methodBodyHeap.Write((byte)0x4a); return;
        case ElementType.UInt32: this.methodBodyHeap.Write((byte)0x4b); return;
        case ElementType.Int64:
        case ElementType.UInt64: this.methodBodyHeap.Write((byte)0x4c); return;
        //case ElementType.UIntPtr:
        //case ElementType.IntPtr: this.methodBodyHeap.Write((byte)0x4d); return;
        case ElementType.Single: this.methodBodyHeap.Write((byte)0x4e); return;
        case ElementType.Double: this.methodBodyHeap.Write((byte)0x4f); return;
        default:
          if (this.UseGenerics && adr.Type != null && adr.Type != SystemTypes.Object){
            this.methodBodyHeap.Write((byte)0x71);
            this.methodBodyHeap.Write((int)this.GetTypeToken(adr.Type));
            return;
          }else if (TypeNode.StripModifiers(adr.Type) is Pointer) {
            this.methodBodyHeap.Write((byte)0x4d); return;
          }
          this.methodBodyHeap.Write((byte)0x50); 
          return;
      }
    }
    void VisitAttributeList(AttributeList attrs, Node/*!*/ node) {
      if (attrs == null) return;
      int n = attrs.Count;
      if (n == 0) return;
      int m = n;
      for (int j = 0; j < n; j++){
        AttributeNode a = attrs[j];
        if (a == null) m--;
      }
      if (m == 0) return;
      n = m;
      int codedIndex = this.GetCustomAttributeParentCodedIndex(node);
      this.customAttributeCount += n;
      m = this.nodesWithCustomAttributes.Count;
      this.nodesWithCustomAttributes.Add(node);
      int i = 0; //after the for loop i will be position where the new node should be in sorted list
      NodeList nodes = this.nodesWithCustomAttributes;
      for (i = m; i > 0; i--){
        Node other = nodes[i-1];
        int oci = this.GetCustomAttributeParentCodedIndex(other);
        if (oci < codedIndex) break;
        if (UseGenerics) {
          if (oci == codedIndex) Debug.Assert(false);
        }
      }
      if (i == m) return; //node is already where it should be
      for (int j = m; j > i; j--) nodes[j] = nodes[j-1]; //Make space at postion i
      nodes[i] = node;
    }
    void VisitAddressOf(UnaryExpression/*!*/ expr) {
      Expression operand = expr.Operand;
      if (operand == null) return;
      switch (operand.NodeType){
        case NodeType.Indexer:
          Indexer indexer = (Indexer)operand;
          this.Visit(indexer.Object);
          if (indexer.Operands == null || indexer.Operands.Count < 1) return;
          this.Visit(indexer.Operands[0]);
          if (expr.NodeType == NodeType.ReadOnlyAddressOf){
            this.methodBodyHeap.Write((byte)0xfe);
            this.methodBodyHeap.Write((byte)0x1e);
          }
          this.methodBodyHeap.Write((byte)0x8f);
          this.methodBodyHeap.Write((int)this.GetTypeToken(indexer.ElementType));
          this.stackHeight--;
          return;
        case NodeType.Local: 
          int li = this.GetLocalVarIndex((Local)operand);
          if (li < 256){
            this.methodBodyHeap.Write((byte)0x12);
            this.methodBodyHeap.Write((byte)li);
          }else{
            this.methodBodyHeap.Write((byte)0xfe);
            this.methodBodyHeap.Write((byte)0x0d);
            this.methodBodyHeap.Write((ushort)li);
          }
          this.IncrementStackHeight();
          return;
        case NodeType.MemberBinding:
          MemberBinding mb = (MemberBinding)operand;
          if (mb.TargetObject != null){
            this.Visit(mb.TargetObject);
            this.methodBodyHeap.Write((byte)0x7c);
          }else{
            this.methodBodyHeap.Write((byte)0x7f);
            this.IncrementStackHeight();
          }
          this.methodBodyHeap.Write((int)this.GetFieldToken((Field)mb.BoundMember));
          return;
        case NodeType.Parameter: 
#if !MinimalReader
          ParameterBinding pb = operand as ParameterBinding;
          if (pb != null) operand = pb.BoundParameter;
#endif
          int pi = ((Parameter)operand).ArgumentListIndex;
          if (pi < 256){
            this.methodBodyHeap.Write((byte)0x0f);
            this.methodBodyHeap.Write((byte)pi);
          }else{
            this.methodBodyHeap.Write((byte)0xfe);
            this.methodBodyHeap.Write((byte)0x0a);
            this.methodBodyHeap.Write((ushort)pi);
          }
          this.IncrementStackHeight();
          return;
        case NodeType.This:
          this.methodBodyHeap.Write((byte)0x02);
          return;
      }
    }
    void VisitAssignmentStatement(AssignmentStatement/*!*/ assignment) {
      this.DefineSequencePoint(assignment);
      Expression target = assignment.Target;
      switch(assignment.Target.NodeType){
        case NodeType.Local:
          Local loc = (Local)target;
          this.Visit(assignment.Source);
          this.stackHeight--;
          int li = this.GetLocalVarIndex(loc);
          switch(li){
            case 0: this.methodBodyHeap.Write((byte)0x0a); return;
            case 1: this.methodBodyHeap.Write((byte)0x0b); return;
            case 2: this.methodBodyHeap.Write((byte)0x0c); return;
            case 3: this.methodBodyHeap.Write((byte)0x0d); return;
            default:
              if (li < 256){
                this.methodBodyHeap.Write((byte)0x13);
                this.methodBodyHeap.Write((byte)li);
              }else{
                this.methodBodyHeap.Write((byte)0xfe);
                this.methodBodyHeap.Write((byte)0x0e);
                this.methodBodyHeap.Write((ushort)li);
              }
              return;
          }
        case NodeType.MemberBinding:
          MemberBinding mb = (MemberBinding)target;
          if (mb.TargetObject != null) this.Visit(mb.TargetObject);
          this.Visit(assignment.Source);
          if (mb.TargetObject != null) {
            if (mb.Alignment != -1) {
              this.methodBodyHeap.Write((byte)0xfe);
              this.methodBodyHeap.Write((byte)0x12);
              this.methodBodyHeap.Write((byte)mb.Alignment);
            }
            if (mb.Volatile) {
              this.methodBodyHeap.Write((byte)0xfe);
              this.methodBodyHeap.Write((byte)0x13);
            }
            this.methodBodyHeap.Write((byte)0x7d);
          } else {
            if (mb.Volatile) {
              this.methodBodyHeap.Write((byte)0xfe);
              this.methodBodyHeap.Write((byte)0x13);
            }
            this.methodBodyHeap.Write((byte)0x80);
          }
          this.methodBodyHeap.Write((int)this.GetFieldToken((Field)mb.BoundMember));
          if (mb.TargetObject != null)
            this.stackHeight -= 2;
          else
            this.stackHeight--;
          return;
        case NodeType.This:
          this.Visit(assignment.Source);
          this.methodBodyHeap.Write((byte)0x10);
          this.methodBodyHeap.Write((byte)0x00);
          this.stackHeight--;
          return;
        case NodeType.Parameter:
#if !MinimalReader
          ParameterBinding pb = target as ParameterBinding;
          if (pb != null) target = pb.BoundParameter;
#endif
          Parameter par = (Parameter)target;
          this.Visit(assignment.Source);
          int pi = par.ArgumentListIndex;
          if (pi < 256){
            this.methodBodyHeap.Write((byte)0x10);
            this.methodBodyHeap.Write((byte)pi);
          }else{
            this.methodBodyHeap.Write((byte)0xfe);
            this.methodBodyHeap.Write((byte)0x0b);
            this.methodBodyHeap.Write((ushort)pi);
          }
          this.stackHeight--;
          return;
        case NodeType.Indexer:
          Indexer indexer = (Indexer)target;
          this.Visit(indexer.Object);
          if (indexer.Operands == null || indexer.Operands.Count < 1) return;
          this.Visit(indexer.Operands[0]);
          this.Visit(assignment.Source);
          byte opCode;
          switch(indexer.ElementType.typeCode){
            case ElementType.UIntPtr:
            case ElementType.IntPtr: opCode = 0x9b; break;
            case ElementType.Boolean:
            case ElementType.Int8:   
            case ElementType.UInt8:  opCode = 0x9c; break;
            case ElementType.Char:
            case ElementType.Int16:  
            case ElementType.UInt16: opCode = 0x9d; break;
            case ElementType.Int32:  
            case ElementType.UInt32: opCode = 0x9e; break;
            case ElementType.Int64:  
            case ElementType.UInt64: opCode = 0x9f; break;
            case ElementType.Single: opCode = 0xa0; break;
            case ElementType.Double: opCode = 0xa1; break;
            default:
              if (this.UseGenerics && indexer.ElementType != null && indexer.ElementType != SystemTypes.Object)
                  opCode = 0xa4;
              else if (TypeNode.StripModifiers(indexer.ElementType) is Pointer)
                opCode = 0x9b;
              else
                opCode = 0xa2; 
              break;
          }
          this.methodBodyHeap.Write((byte)opCode);
          if (opCode == 0xa4) this.methodBodyHeap.Write((int)this.GetTypeToken(indexer.ElementType));
          this.stackHeight -= 3;
          return;
        case NodeType.AddressDereference:
          AddressDereference adr = (AddressDereference)target;
          this.Visit(adr.Address);
          if (adr.Type != null){
            Literal lit = assignment.Source as Literal;
            if (lit != null && lit.Value == null){
              if (adr.Type == SystemTypes.Object) {
                this.methodBodyHeap.Write((byte)OpCode.Ldnull);
                this.IncrementStackHeight();
                this.methodBodyHeap.Write((byte)OpCode.Stind_Ref);
                this.stackHeight-=2;
              } else {
                this.methodBodyHeap.Write((byte)0xfe);
                this.methodBodyHeap.Write((byte)0x15);
                this.methodBodyHeap.Write((int)this.GetTypeToken(adr.Type));
                this.stackHeight--;
              }
              return;
            }
          }
          this.Visit(assignment.Source);
          this.stackHeight -= 2;
          if (adr.Alignment > 0){
            this.methodBodyHeap.Write((byte)0xfe);
            this.methodBodyHeap.Write((byte)0x12);
            this.methodBodyHeap.Write((byte)adr.Alignment);
          }
          if (adr.Volatile){
            this.methodBodyHeap.Write((byte)0xfe);
            this.methodBodyHeap.Write((byte)0x13);
          }
          TypeNode adrType = TypeNode.StripModifiers(adr.Type);
          if (adrType == null) return;
          switch(adrType.typeCode){
            case ElementType.Int8:   
            case ElementType.UInt8:  this.methodBodyHeap.Write((byte)0x52); return;
            case ElementType.Int16:  
            case ElementType.UInt16: this.methodBodyHeap.Write((byte)0x53); return;
            case ElementType.Int32:  
            case ElementType.UInt32: this.methodBodyHeap.Write((byte)0x54); return;
            case ElementType.Int64:
            case ElementType.UInt64: this.methodBodyHeap.Write((byte)0x55); return;
            case ElementType.Single: this.methodBodyHeap.Write((byte)0x56); return;
            case ElementType.Double: this.methodBodyHeap.Write((byte)0x57); return;
            case ElementType.UIntPtr:
            case ElementType.IntPtr: this.methodBodyHeap.Write((byte)0xdf); return;
            default:
              if (this.UseGenerics && adrType != null && adrType != SystemTypes.Object){
                this.methodBodyHeap.Write((byte)0x81);
                this.methodBodyHeap.Write((int)this.GetTypeToken(adrType));
                return;
              }
              if (adrType.NodeType == NodeType.Pointer) {
                this.methodBodyHeap.Write((byte)0xdf); return;
              }
              this.methodBodyHeap.Write((byte)0x51);
              return;
          }
        default:
          Debug.Assert(false, "unexpected assignment target");
          return;
      }
    }
#if !MinimalReader && !CodeContracts
    void VisitBase(Base/*!*/ Base) {
      this.IncrementStackHeight();
      this.methodBodyHeap.Write((byte)0x02);
    }
#endif
    void VisitBinaryExpression(BinaryExpression/*!*/ binaryExpression) {
      byte opCode = 0;
      this.Visit(binaryExpression.Operand1);
      switch(binaryExpression.NodeType){
        case NodeType.Castclass : opCode = 0x74; goto writeOpCodeAndToken;
        case NodeType.Isinst :    opCode = 0x75; goto writeOpCodeAndToken;
        case NodeType.Unbox :     opCode = 0x79; goto writeOpCodeAndToken;
        case NodeType.UnboxAny :  opCode = 0xa5; goto writeOpCodeAndToken;
        case NodeType.Box :       opCode = 0x8c; goto writeOpCodeAndToken;
        case NodeType.Refanyval : opCode = 0xc2; goto writeOpCodeAndToken;
        case NodeType.Mkrefany :  opCode = 0xc6; goto writeOpCodeAndToken;
        writeOpCodeAndToken:
          this.methodBodyHeap.Write((byte)opCode);
          Literal lit = binaryExpression.Operand2 as Literal;
          if (lit != null)
            this.methodBodyHeap.Write((int)this.GetTypeToken((TypeNode)lit.Value));
          else{
            // TODO: Normalized IR should never use a MemberBinding to represent a type
            this.methodBodyHeap.Write((int)this.GetTypeToken((TypeNode)((MemberBinding)binaryExpression.Operand2).BoundMember));
          }
          return;
        case NodeType.Ldvirtftn : opCode = 0x07; this.methodBodyHeap.Write((byte)0xfe); 
          this.methodBodyHeap.Write((byte)opCode);
          this.methodBodyHeap.Write((int)this.GetMethodToken((Method)((MemberBinding)binaryExpression.Operand2).BoundMember));
          return;
      }
      this.Visit(binaryExpression.Operand2);
      switch(binaryExpression.NodeType){
        case NodeType.Add :    opCode = 0x58; break;
        case NodeType.Sub :    opCode = 0x59; break;
        case NodeType.Mul :    opCode = 0x5a; break;
        case NodeType.Div :    opCode = 0x5b; break;
        case NodeType.Div_Un : opCode = 0x5c; break;
        case NodeType.Rem :    opCode = 0x5d; break;
        case NodeType.Rem_Un : opCode = 0x5e; break;
        case NodeType.And :    opCode = 0x5f; break;
        case NodeType.Or :     opCode = 0x60; break;
        case NodeType.Xor :    opCode = 0x61; break;
        case NodeType.Shl :    opCode = 0x62; break;
        case NodeType.Shr :    opCode = 0x63; break;
        case NodeType.Shr_Un : opCode = 0x64; break;
        case NodeType.Add_Ovf:     opCode = 0xd6; break;
        case NodeType.Add_Ovf_Un : opCode = 0xd7; break;
        case NodeType.Mul_Ovf :    opCode = 0xd8; break;
        case NodeType.Mul_Ovf_Un : opCode = 0xd9; break;
        case NodeType.Sub_Ovf :    opCode = 0xda; break;
        case NodeType.Sub_Ovf_Un : opCode = 0xdb; break;
        case NodeType.Ceq :    opCode = 0x01; this.methodBodyHeap.Write((byte)0xfe); break;
        case NodeType.Cgt :    opCode = 0x02; this.methodBodyHeap.Write((byte)0xfe); break;
        case NodeType.Cgt_Un : opCode = 0x03; this.methodBodyHeap.Write((byte)0xfe); break;
        case NodeType.Clt :    opCode = 0x04; this.methodBodyHeap.Write((byte)0xfe); break;
        case NodeType.Clt_Un : opCode = 0x05; this.methodBodyHeap.Write((byte)0xfe); break;
      }
      this.methodBodyHeap.Write((byte)opCode);
      this.stackHeight--;
    }
    void VisitBlock(Block/*!*/ block) {
      MethodInfo mInfo = this.methodInfo;
      int currentAddress = (int)this.methodBodyHeap.BaseStream.Position;
      this.VisitFixupList(this.methodInfo.fixupIndex[block.UniqueKey] as Fixup, currentAddress);
      mInfo.fixupIndex[block.UniqueKey] = currentAddress;
      this.methodBodyHeap.BaseStream.Position = currentAddress;
      int savedStackHeight = this.stackHeight;
      if (this.exceptionBlock[block.UniqueKey] != null) this.stackHeight = 1;
      StatementList statements = block.Statements;
      if (statements == null) return;
#if !ROTOR
      if (this.symWriter != null && block.HasLocals){
        LocalList savedDebugLocals = mInfo.debugLocals;
        Int32List savedSignatureLengths = mInfo.signatureLengths;
        Int32List savedSignatureOffsets = mInfo.signatureOffsets;
        mInfo.debugLocals = new LocalList();
        mInfo.signatureLengths = new Int32List();
        mInfo.signatureOffsets = new Int32List();
        this.symWriter.OpenScope((uint)currentAddress);
        for (int i = 0, n = statements.Count; i < n; i++)
          this.Visit(statements[i]);
        if (this.stackHeight > 0) this.stackHeightExitTotal += this.stackHeight;
        this.DefineLocalVariables(currentAddress, mInfo.debugLocals);
        mInfo.debugLocals = savedDebugLocals;
        mInfo.signatureLengths = savedSignatureLengths;
        mInfo.signatureOffsets = savedSignatureOffsets;
      }else{
#endif
        for (int i = 0, n = statements.Count; i < n; i++)
          this.Visit(statements[i]);
        if (this.stackHeight > savedStackHeight) this.stackHeightExitTotal += (this.stackHeight - savedStackHeight);
#if !ROTOR
      }
#endif
      this.stackHeight = savedStackHeight;
    }
#if !MinimalReader
    void VisitBlockExpression(BlockExpression/*!*/ blockExpression) {
      if (blockExpression.Block == null) return;
      this.VisitBlock(blockExpression.Block);
    }
#endif
    void VisitBranch(Branch/*!*/ branch) {
      this.DefineSequencePoint(branch);
      BinaryExpression bex = branch.Condition as BinaryExpression;
      UnaryExpression uex = null;
      NodeType typeOfCondition = NodeType.Nop;
      if (bex != null){
        switch(bex.NodeType){
          case NodeType.Eq:
          case NodeType.Ge:
          case NodeType.Gt:
          case NodeType.Le:
          case NodeType.Lt:
          case NodeType.Ne:
            this.Visit(bex.Operand1);
            this.Visit(bex.Operand2);
            typeOfCondition = bex.NodeType;
            this.stackHeight -= 2;
            break;
          case NodeType.And:
          case NodeType.Or:
          case NodeType.Xor:
          case NodeType.Isinst:
          case NodeType.Castclass:
            typeOfCondition = bex.NodeType;
            goto default;
          default:
            this.Visit(branch.Condition);
            this.stackHeight--;
            break;
        }
      }else{
        uex = branch.Condition as UnaryExpression;
        if (uex != null && uex.NodeType == NodeType.LogicalNot) {
          this.Visit(uex.Operand);
          typeOfCondition = NodeType.LogicalNot;
          this.stackHeight--;
        }else if (branch.Condition != null){
          // Undefined is used here simply as a sentinel value
          typeOfCondition = NodeType.Undefined;
          this.Visit(branch.Condition);
          this.stackHeight--;
        }
      }
      int target = this.GetOffset(branch.Target, ref branch.shortOffset);
      if (branch.ShortOffset){
        switch(typeOfCondition){
          case NodeType.Nop:
            if (branch.Condition == null){
              if (branch.LeavesExceptionBlock)
                this.methodBodyHeap.Write((byte)0xde);
              else
                this.methodBodyHeap.Write((byte)0x2b);
              break;
            }else{
              this.methodBodyHeap.Write((byte)0x2d); break;
            }
          case NodeType.And:
          case NodeType.Or:
          case NodeType.Xor:
          case NodeType.Isinst:
          case NodeType.Castclass:
          case NodeType.Undefined:
            this.methodBodyHeap.Write((byte)0x2d); break;
          case NodeType.LogicalNot:
            this.methodBodyHeap.Write((byte)0x2c); break;
          case NodeType.Eq:
            this.methodBodyHeap.Write((byte)0x2e); break;
          case NodeType.Ge:
            if (branch.BranchIfUnordered)
              this.methodBodyHeap.Write((byte)0x34);
            else
              this.methodBodyHeap.Write((byte)0x2f);
            break;
          case NodeType.Gt:
            if (branch.BranchIfUnordered)
              this.methodBodyHeap.Write((byte)0x35);
            else
              this.methodBodyHeap.Write((byte)0x30);
            break;
          case NodeType.Le:
            if (branch.BranchIfUnordered)
              this.methodBodyHeap.Write((byte)0x36);
            else
              this.methodBodyHeap.Write((byte)0x31);
            break;
          case NodeType.Lt:
            if (branch.BranchIfUnordered)
              this.methodBodyHeap.Write((byte)0x37);
            else
              this.methodBodyHeap.Write((byte)0x32);
            break;
          case NodeType.Ne:
            this.methodBodyHeap.Write((byte)0x33);
            break;
        }
        this.methodBodyHeap.Write((sbyte)target);
      }else{
        switch(typeOfCondition){
          case NodeType.Nop:
            if (branch.Condition == null){
              if (branch.LeavesExceptionBlock)
                this.methodBodyHeap.Write((byte)0xdd);
              else
                this.methodBodyHeap.Write((byte)0x38);
              break;
            }else{
              this.methodBodyHeap.Write((byte)0x3a); break;
            }
          case NodeType.And:
          case NodeType.Or:
          case NodeType.Xor:
          case NodeType.Isinst:
          case NodeType.Castclass:
          case NodeType.Undefined:
            this.methodBodyHeap.Write((byte)0x3a); break;
          case NodeType.LogicalNot:
            this.methodBodyHeap.Write((byte)0x39); break;
          case NodeType.Eq:
            this.methodBodyHeap.Write((byte)0x3b); break;
          case NodeType.Ge:
            if (branch.BranchIfUnordered)
              this.methodBodyHeap.Write((byte)0x41);
            else
              this.methodBodyHeap.Write((byte)0x3c);
            break;
          case NodeType.Gt:
            if (branch.BranchIfUnordered)
              this.methodBodyHeap.Write((byte)0x42);
            else
              this.methodBodyHeap.Write((byte)0x3d);
            break;
          case NodeType.Le:
            if (branch.BranchIfUnordered)
              this.methodBodyHeap.Write((byte)0x43);
            else
              this.methodBodyHeap.Write((byte)0x3e);
            break;
          case NodeType.Lt:
            if (branch.BranchIfUnordered)
              this.methodBodyHeap.Write((byte)0x44);
            else
              this.methodBodyHeap.Write((byte)0x3f);
            break;
          case NodeType.Ne:
            this.methodBodyHeap.Write((byte)0x40); break;
        }
        this.methodBodyHeap.Write((int)target);
      }
    }
    void VisitMethodCall(MethodCall/*!*/ call) {
      MemberBinding mb = (MemberBinding)call.Callee;
      TypeNode constraint = call.Constraint;
      this.Visit(mb.TargetObject);
      ExpressionList arguments = call.Operands;
      int pops = 0;
      if (arguments != null){
        this.VisitExpressionList(arguments);
        pops = arguments.Count;
      }
      if (call.Type != CoreSystemTypes.Void) { this.VisitReferencedType(call.Type); pops--; }
      if (pops >= 0)
        this.stackHeight -= pops;
      else
        this.IncrementStackHeight(); //make sure the high water mark moves up if necessary
      if (call.IsTailCall){
        this.methodBodyHeap.Write((byte)0xfe);
        this.methodBodyHeap.Write((byte)0x14);
      }else if (constraint != null){
        this.methodBodyHeap.Write((byte)0xfe);
        this.methodBodyHeap.Write((byte)0x16);
        this.methodBodyHeap.Write((int)this.GetTypeToken(constraint));
      }
      switch (call.NodeType){
        case NodeType.Calli: 
          this.methodBodyHeap.Write((byte)0x29);
          BinaryWriter sig = new BinaryWriter(new MemoryStream());
          this.WriteMethodSignature(sig, (FunctionPointer)mb.BoundMember);
          this.methodBodyHeap.Write((int)(0x11000000 | this.GetStandAloneSignatureIndex(sig)));
          return;
        case NodeType.Callvirt: this.methodBodyHeap.Write((byte)0x6f); break;
        case NodeType.Jmp: this.methodBodyHeap.Write((byte)0x27); break;
        default: this.methodBodyHeap.Write((byte)0x28); break;
      }
      Method method = (Method)mb.BoundMember;
      if ((method.CallingConvention&(CallingConventionFlags)7) == CallingConventionFlags.VarArg || 
        (method.CallingConvention&(CallingConventionFlags)7) == CallingConventionFlags.C){
        this.methodBodyHeap.Write((int)this.GetMemberRefToken(method, arguments));
      }else
        this.methodBodyHeap.Write((int)this.GetMethodToken(method));
    }
    void VisitClass(Class/*!*/ Class) {
      if (this.UseGenerics && Class.Template != null && Class.Template.IsGeneric) return;
      this.VisitAttributeList(Class.Attributes, Class);
      this.VisitSecurityAttributeList(Class.SecurityAttributes, Class);
      if (Class.BaseClass != null) this.VisitReferencedType(Class.BaseClass);
      for (int i = 0, n = Class.Interfaces == null ? 0 : Class.Interfaces.Count; i < n; i++) {
        this.GetTypeDefOrRefOrSpecEncoded(Class.Interfaces[i]);
        if (Class.Interfaces[i] != null) this.interfaceEntries.Add(Class);
      }
      if (Class.NodeType == NodeType.ClassParameter && !(Class is MethodClassParameter))
        this.interfaceEntries.Add(Class);
      for (int i = 0, n = Class.Members.Count; i < n; i++){
        Member mem = Class.Members[i];
        if (mem == null || mem is TypeNode) continue;
        this.Visit(mem);
      }
      if ((Class.Flags & (TypeFlags.ExplicitLayout|TypeFlags.SequentialLayout)) != 0 && (Class.PackingSize != 0 || Class.ClassSize != 0))
        this.classLayoutEntries.Add(Class);
    }
    void VisitConstruct(Construct/*!*/ cons) {
      int pops = -1;
      ExpressionList operands = cons.Operands;
      if (operands != null){
        this.VisitExpressionList(cons.Operands);
        pops = operands.Count - 1;
      }
      if (pops >= 0)
        this.stackHeight -= pops;
      else
        this.IncrementStackHeight();
      this.methodBodyHeap.Write((byte)0x73);
      Method method = ((MemberBinding)cons.Constructor).BoundMember as Method;
      if (method == null) return;
      this.methodBodyHeap.Write((int)this.GetMethodToken(method)); //REVIEW: varargs?
    }
    void VisitConstructArray(ConstructArray/*!*/ consArr) {
      if (consArr == null || consArr.Operands == null || consArr.Operands.Count < 1) return;
      this.Visit(consArr.Operands[0]);
      this.methodBodyHeap.Write((byte)0x8d);
      this.methodBodyHeap.Write((int)this.GetTypeToken(consArr.ElementType));
    }
    void VisitDelegateNode(DelegateNode/*!*/ delegateNode) {
      if (this.UseGenerics && delegateNode.Template != null && delegateNode.Template.IsGeneric) return;
      this.VisitAttributeList(delegateNode.Attributes, delegateNode);
      this.VisitSecurityAttributeList(delegateNode.SecurityAttributes, delegateNode);
      this.VisitReferencedType(CoreSystemTypes.MulticastDelegate);
      for (int i = 0, n = delegateNode.Interfaces == null ? 0 : delegateNode.Interfaces.Count; i < n; i++) { //REVIEW: is this valid?
        this.GetTypeDefOrRefOrSpecEncoded(delegateNode.Interfaces[i]);
        if (delegateNode.Interfaces[i] != null) this.interfaceEntries.Add(delegateNode);
      }
      for (int i = 0, n = delegateNode.Members.Count; i < n; i++){
        Member mem = delegateNode.Members[i];
        if (mem == null || mem is TypeNode) continue;
        this.Visit(mem);
      }
    }
    void VisitEndFilter(EndFilter/*!*/ endFilter) {
      this.DefineSequencePoint(endFilter);
      this.Visit(endFilter.Value);
      this.methodBodyHeap.Write((byte)0xfe);
      this.methodBodyHeap.Write((byte)0x11);
      this.stackHeight--;
    }
    void VisitEnumNode(EnumNode/*!*/ enumNode) {
      this.VisitAttributeList(enumNode.Attributes, enumNode);
      this.VisitSecurityAttributeList(enumNode.SecurityAttributes, enumNode);
      this.VisitReferencedType(CoreSystemTypes.Enum);
      for (int i = 0, n = enumNode.Interfaces == null ? 0 : enumNode.Interfaces.Count; i < n; i++) {
        this.GetTypeDefOrRefOrSpecEncoded(enumNode.Interfaces[i]);
        if (enumNode.Interfaces[i] != null) this.interfaceEntries.Add(enumNode);
      }
      for (int i = 0, n = enumNode.Members.Count; i < n; i++)
        this.Visit(enumNode.Members[i]);
    }
    void VisitEvent(Event/*!*/ Event) {
      object eindex = this.eventIndex[Event.UniqueKey];
      if (eindex != null) return;
      int index = this.eventEntries.Count+1;
      this.eventEntries.Add(Event);
      this.eventIndex[Event.UniqueKey] = index;
      object evindex = this.eventMapIndex[Event.DeclaringType.UniqueKey];
      if (evindex == null){
        this.eventMapEntries.Add(Event);
        this.eventMapIndex[Event.DeclaringType.UniqueKey] = this.eventMapEntries.Count;
      }
      if (Event.HandlerAdder != null) this.methodSemanticsEntries.Add(Event);
      if (Event.HandlerRemover != null) this.methodSemanticsEntries.Add(Event);
      if (Event.HandlerCaller != null) this.methodSemanticsEntries.Add(Event);
      if (Event.OtherMethods != null)
        for (int i = 0, n = Event.OtherMethods.Count; i < n; i++) 
          this.methodSemanticsEntries.Add(Event);
      this.VisitAttributeList(Event.Attributes, Event);
    }
    void VisitExpression(Expression/*!*/ expression) {
      switch(expression.NodeType){
        case NodeType.Dup: 
          this.methodBodyHeap.Write((byte)0x25); 
          this.IncrementStackHeight();
          return;
        case NodeType.Pop:
          UnaryExpression unex = expression as UnaryExpression;
          if (unex != null){
            this.Visit(unex.Operand);
            this.stackHeight--;
            this.methodBodyHeap.Write((byte)0x26);
          }
          return;
        case NodeType.Arglist:
          this.IncrementStackHeight();
          this.methodBodyHeap.Write((byte)0xfe);
          this.methodBodyHeap.Write((byte)0x00);
          return;
      }
    }
    void VisitExpressionList(ExpressionList expressions){
      if (expressions == null) return;
      for (int i = 0, n = expressions.Count; i < n; i++)
        this.Visit(expressions[i]);
    }
    void VisitExpressionStatement(ExpressionStatement/*!*/ statement) {
#if !MinimalReader
      if (!(statement.Expression is BlockExpression))
#endif
        this.DefineSequencePoint(statement);
      this.Visit(statement.Expression);
    }
    void VisitField(Field/*!*/ field) {
      this.VisitAttributeList(field.Attributes, field);
      this.GetFieldIndex(field);
      if (field.IsVolatile)
        field.Type = RequiredModifier.For(CoreSystemTypes.IsVolatile, field.Type);
      this.VisitReferencedType(field.Type);
    }
    void VisitFixupList(Fixup fixup, int targetAddress) {
      while (fixup != null){
        this.methodBodyHeap.BaseStream.Position = fixup.fixupLocation;
        if (fixup.shortOffset){
          int offset = targetAddress - fixup.addressOfNextInstruction;
          Debug.Assert(-128 <= offset && offset <= 127, "Invalid short branch");
          this.methodBodyHeap.Write((byte)offset);
        }else
          this.methodBodyHeap.Write((int)(targetAddress - fixup.addressOfNextInstruction));
        fixup = fixup.nextFixUp;
      }
    }
    void VisitGenericParameterList(Member/*!*/ member, TypeNodeList/*!*/ parameters) {
      if (member == null || parameters == null || !this.UseGenerics) return;
      int sign = member is Method ? -1 : 1;
      for (int i = 0, n = parameters.Count; i < n; i++){
        TypeNode parameter = parameters[i];
        if (parameter == null) continue;
        this.typeParameterNumber[parameter.UniqueKey] = sign*(i+1);
        this.genericParamEntries.Add(member);
        if (((ITypeParameter)parameter).DeclaringMember != member)
          parameter = (TypeNode)parameter.Clone();
        this.genericParameters.Add(parameter);
#if CodeContracts
        for (int j = 0, m = parameter.StructuralElementTypes == null ? 0 : parameter.StructuralElementTypes.Count; j < m; j++)
          this.genericParamConstraintEntries.Add(parameter);
#else
        if (parameter.BaseType is Class && parameter.BaseType != CoreSystemTypes.Object)
          this.genericParamConstraintEntries.Add(parameter);
        for (int j = 0, m = parameter.Interfaces == null ? 0 : parameter.Interfaces.Count; j < m; j++)
          this.genericParamConstraintEntries.Add(parameter);
#endif
      }
    }
    void VisitIndexer(Indexer/*!*/ indexer) {
      this.Visit(indexer.Object);
      if (indexer.Operands == null || indexer.Operands.Count < 1) return;
      this.Visit(indexer.Operands[0]);
      byte opCode;
      switch(indexer.ElementType.typeCode){
        case ElementType.Boolean:
        case ElementType.Int8:   opCode = 0x90; break;
        case ElementType.UInt8:  opCode = 0x91; break;
        case ElementType.Int16:  opCode = 0x92; break;
        case ElementType.Char:
        case ElementType.UInt16: opCode = 0x93; break;
        case ElementType.Int32:  opCode = 0x94; break;
        case ElementType.UInt32: opCode = 0x95; break;
        case ElementType.Int64:  
        case ElementType.UInt64: opCode = 0x96; break;
        case ElementType.UIntPtr:
        case ElementType.IntPtr: opCode = 0x97; break;
        case ElementType.Single: opCode = 0x98; break;
        case ElementType.Double: opCode = 0x99; break;
        default:
          if (this.UseGenerics && indexer.ElementType != null && indexer.ElementType != SystemTypes.Object)
              opCode = 0xa3;
          else if (TypeNode.StripModifiers(indexer.ElementType) is Pointer)
            opCode = 0x97;
          else
            opCode = 0x9a;
          break;
      }
      this.methodBodyHeap.Write((byte)opCode);
      if (opCode == 0xa3) this.methodBodyHeap.Write((int)this.GetTypeToken(indexer.ElementType));
      this.stackHeight--;
    }
    void VisitInterface(Interface/*!*/ Interface) {
      if (this.UseGenerics && Interface.Template != null && Interface.Template.IsGeneric) return;
      this.VisitAttributeList(Interface.Attributes, Interface);
      this.VisitSecurityAttributeList(Interface.SecurityAttributes, Interface);
      InterfaceList interfaces = Interface.Interfaces;
      for (int i = 0, n = interfaces == null ? 0 : interfaces.Count; i < n; i++) {
        this.GetTypeDefOrRefOrSpecEncoded(interfaces[i]);
        if (interfaces[i] != null) this.interfaceEntries.Add(Interface);
      }
      if (Interface.NodeType == NodeType.TypeParameter && !(Interface is MethodTypeParameter))
        this.interfaceEntries.Add(Interface);
      for (int i = 0, n = Interface.Members.Count; i < n; i++){
        Member mem = Interface.Members[i];
        if (mem == null || mem is TypeNode) continue;
        this.Visit(mem);
      }
    }
    void VisitLocal(Local/*!*/ local) {
      this.IncrementStackHeight();
      int li = this.GetLocalVarIndex(local);
      switch(li){
        case 0: this.methodBodyHeap.Write((byte)0x06); return;
        case 1: this.methodBodyHeap.Write((byte)0x07); return;
        case 2: this.methodBodyHeap.Write((byte)0x08); return;
        case 3: this.methodBodyHeap.Write((byte)0x09); return;
        default:
          if (li < 256){
            this.methodBodyHeap.Write((byte)0x11);
            this.methodBodyHeap.Write((byte)li);
          }else{
            this.methodBodyHeap.Write((byte)0xfe);
            this.methodBodyHeap.Write((byte)0x0c);
            this.methodBodyHeap.Write((ushort)li);
          }
          return;
      }
    }
#if !MinimalReader && !CodeContracts
    /// <summary>
    /// This just gets the local variable index for each local declaration.
    /// That associates the debug information with the right block because
    /// it is the block the local is declared in rather than the subblock
    /// it is first referenced in. (When different, the debugger only knows
    /// about the local when control is in the subblock.)
    /// </summary>
    /// <param name="localDeclarations">The list of locals declared at this statement</param>
    void VisitLocalDeclarationsStatement(LocalDeclarationsStatement/*!*/ localDeclarations) {
      if (localDeclarations == null) return;
      LocalDeclarationList decls = localDeclarations.Declarations;
      for (int i = 0, n = decls == null ? 0 : decls.Count; i < n; i++) {
        //^ assert decls != null;
        LocalDeclaration decl = decls[i];
        if (decl == null) continue;
        Field f = decl.Field;
        if (f == null) continue;
        //^ assume this.currentMethod != null;
        Local loc = this.currentMethod.GetLocalForField(f);
        loc.Type = localDeclarations.Type;
        this.GetLocalVarIndex(loc);
      }
    }
#endif
    void VisitLiteral(Literal/*!*/ literal) {
      this.IncrementStackHeight();
      IConvertible ic = literal.Value as IConvertible;
      if (ic == null){
        Debug.Assert(literal.Value == null && !literal.Type.IsValueType);
        this.methodBodyHeap.Write((byte)0x14); return;
      }
      TypeCode tc = ic.GetTypeCode();
      switch (tc){
        case TypeCode.Boolean:
        case TypeCode.SByte:
        case TypeCode.Byte:
        case TypeCode.Char:
        case TypeCode.Int16:
        case TypeCode.UInt16:
        case TypeCode.Int32:
        case TypeCode.UInt32:
        case TypeCode.Int64:
          long n = ic.ToInt64(null);
          switch (n){
            case -1 : this.methodBodyHeap.Write((byte)0x15); break;
            case 0 : this.methodBodyHeap.Write((byte)0x16); break;
            case 1 : this.methodBodyHeap.Write((byte)0x17); break;
            case 2 : this.methodBodyHeap.Write((byte)0x18); break;
            case 3 : this.methodBodyHeap.Write((byte)0x19); break;
            case 4 : this.methodBodyHeap.Write((byte)0x1a); break;
            case 5 : this.methodBodyHeap.Write((byte)0x1b); break;
            case 6 : this.methodBodyHeap.Write((byte)0x1c); break;
            case 7 : this.methodBodyHeap.Write((byte)0x1d); break;
            case 8 : this.methodBodyHeap.Write((byte)0x1e); break;
            default:
              if (n >= System.SByte.MinValue && n <= System.SByte.MaxValue){
                this.methodBodyHeap.Write((byte)0x1f);
                this.methodBodyHeap.Write((byte)n);
              }else if (n >= System.Int32.MinValue && n <= System.Int32.MaxValue ||
                n <= System.UInt32.MaxValue && (tc == TypeCode.Char || tc == TypeCode.UInt16 || tc == TypeCode.UInt32)){
                if (n == System.UInt32.MaxValue && tc != TypeCode.Int64)
                  this.methodBodyHeap.Write((byte)0x15);
                else{
                  this.methodBodyHeap.Write((byte)0x20);
                  this.methodBodyHeap.Write((int)n);
                }
              }else{
                this.methodBodyHeap.Write((byte)0x21);
                this.methodBodyHeap.Write((long)n);
                tc = TypeCode.Empty; //Suppress conversion to long
              }
              break;
          }
          if (tc == TypeCode.Int64)
            this.methodBodyHeap.Write((byte)0x6a);
          return;

        case TypeCode.UInt64:
          this.methodBodyHeap.Write((byte)0x21);
          this.methodBodyHeap.Write(ic.ToUInt64(null));
          return;

        case TypeCode.Single:
          this.methodBodyHeap.Write((byte)0x22);
          this.methodBodyHeap.Write(ic.ToSingle(null));
          return;

        case TypeCode.Double:
          this.methodBodyHeap.Write((byte)0x23);
          this.methodBodyHeap.Write(ic.ToDouble(null));
          return;

        case TypeCode.String:
          this.methodBodyHeap.Write((byte)0x72);
          this.methodBodyHeap.Write((int)(this.GetUserStringIndex((String)literal.Value)|0x70000000));
          return;
      }
      Debug.Assert(false, "Unexpected literal type");
    }
    void VisitMemberBinding(MemberBinding/*!*/ memberBinding) {
      if (memberBinding.TargetObject != null) {
        this.Visit(memberBinding.TargetObject);
        if (memberBinding.Volatile) {
          this.methodBodyHeap.Write((byte)0xfe);
          this.methodBodyHeap.Write((byte)0x13);
        }
        this.methodBodyHeap.Write((byte)0x7b);
      }else{
        this.IncrementStackHeight();
        if (memberBinding.Volatile) {
          this.methodBodyHeap.Write((byte)0xfe);
          this.methodBodyHeap.Write((byte)0x13);
        }
        this.methodBodyHeap.Write((byte)0x7e);
      }
      this.methodBodyHeap.Write((int)this.GetFieldToken((Field)memberBinding.BoundMember));
      return;
    }
    void VisitMethod(Method/*!*/ method) {
      if (this.UseGenerics && method.Template != null && method.Template.IsGeneric) return;
      this.GetMethodIndex(method);
      this.VisitAttributeList(method.Attributes, method);
      this.VisitSecurityAttributeList(method.SecurityAttributes, method);
      for (int i = 0, n = method.Parameters == null ? 0 : method.Parameters.Count; i < n; i++){
        Parameter par = method.Parameters[i];
        if (par == null) continue;
        this.VisitAttributeList(par.Attributes, par);
        this.VisitReferencedType(par.Type);
      }
      if (method.ReturnType != null)
        this.VisitReferencedType(method.ReturnType);
      if (!method.IsAbstract && method.Body != null){
        if (method.Body.Statements != null && method.Body.Statements.Count > 0)
          this.VisitMethodBody(method);
      }
      MethodList implementedInterfaceMethods = method.ImplementedInterfaceMethods;
      for (int i = 0, n = implementedInterfaceMethods == null ? 0 : implementedInterfaceMethods.Count; i < n; i++){
        Method im = implementedInterfaceMethods[i];
        if (im == null) continue;
        this.methodImplEntries.Add(method);
      }
      if ((method.Flags & MethodFlags.PInvokeImpl) != 0 && method.PInvokeImportName != null && method.PInvokeModule != null){
        this.implMapEntries.Add(method);
        this.GetStringIndex(method.PInvokeImportName);
        this.GetModuleRefIndex(method.PInvokeModule);
      }
    }
    void VisitMethodBody(Method/*!*/ method) {
      //Visit body, emitting IL bytes and gathering information
      this.methodBodyHeap = new BinaryWriter(new MemoryStream());
      this.methodInfo = new MethodInfo();
#if !MinimalReader && !CodeContracts
      this.currentMethod = method;
#endif
      this.stackHeightMax = 0;
      this.stackHeightExitTotal = 0;
      uint methodDefToken = 0;
#if !ROTOR
      if (this.symWriter != null){
        methodDefToken = (uint)this.GetMethodDefToken(method);
        this.methodInfo.debugLocals = new LocalList();
        this.methodInfo.signatureLengths = new Int32List();
        this.methodInfo.signatureOffsets = new Int32List();
        this.methodInfo.statementNodes = new NodeList();
        this.methodInfo.statementOffsets = new Int32List();
        this.symWriter.OpenMethod(methodDefToken);
        this.symWriter.OpenScope(0u);
#if !MinimalReader && !CodeContracts
        MethodScope scope = method.Scope;
        if (scope != null){
          UsedNamespaceList usedNamespaces = scope.UsedNamespaces;
          for (int i = 0, n = usedNamespaces == null ? 0 : usedNamespaces.Count; i < n; i++) {
            //^ assert usedNamespaces != null;
            UsedNamespace uns = usedNamespaces[i];
            if (uns == null || uns.Namespace == null) continue;
            this.symWriter.UsingNamespace(uns.Namespace.ToString());
          }
        }
#endif
      }
#endif
#if !FxCop
      int originalAddress = 0;
      if (method.LocalList != null) {
        for (int i = 0, n = method.LocalList.Count; i < n; i++) {
          Local loc = method.LocalList[i];
          if (loc == null) continue;
          this.GetLocalVarIndex(loc);
        }
#if !ROTOR
        if (this.symWriter != null) {
          int currentAddress = (int)this.methodBodyHeap.BaseStream.Position;
          originalAddress = currentAddress;
          this.symWriter.OpenScope((uint)currentAddress);
        }
#endif
      }
#endif
      int exceptionHandlersCount = method.ExceptionHandlers == null ? 0 : method.ExceptionHandlers.Count;
      if (exceptionHandlersCount > 0){
        this.exceptionBlock = new TrivialHashtable();
        for (int i = 0; i < exceptionHandlersCount; i++){
          ExceptionHandler eh = method.ExceptionHandlers[i];
          if (eh == null || eh.HandlerStartBlock == null || (eh.HandlerType != NodeType.Catch && eh.HandlerType != NodeType.Filter)) continue;
          this.exceptionBlock[eh.HandlerStartBlock.UniqueKey] = eh;
        }
      }
      this.VisitBlock(method.Body);

#if !FxCop
      if (method.LocalList != null) {
#if !ROTOR
        if (this.symWriter != null) {
          DefineLocalVariables(originalAddress, method.LocalList);
        }
#endif
      }
#endif
      
      this.methodBodiesHeapIndex[method.UniqueKey] = (int)this.methodBodiesHeap.BaseStream.Position;
      int maxStack = this.stackHeightExitTotal + this.stackHeightMax; //Wildly pessimistic estimate. Works dandy if BBlocks never leave anything on the stack.
      if (exceptionHandlersCount > 0 && maxStack == 0) maxStack = 1;
      int codeSize = (int)this.methodBodyHeap.BaseStream.Position;
      int localVarSigTok = this.methodInfo.localVarSigTok;
      bool fatHeader = codeSize >= 64 || exceptionHandlersCount > 0 || maxStack > 8 || localVarSigTok != 0;
      if (fatHeader) {
        //Emit fat header
        byte header = 0x03;
        if (method.InitLocals) header |= 0x10;
        if (exceptionHandlersCount > 0) header |= 0x08;
        this.methodBodiesHeap.Write((byte)header);
        this.methodBodiesHeap.Write((byte)0x30); //top 4 bits represent length of fat header in dwords. Heaven only knows why.
        this.methodBodiesHeap.Write((short)maxStack);
        this.methodBodiesHeap.Write((int)codeSize);
        if (localVarSigTok != 0){
          if (this.methodInfo.localVarIndex.Count > 127){
            //Need to make space for the two byte count
            this.methodInfo.localVarSignature.Write((byte)0);
            byte[] buf = this.methodInfo.localVarSignature.BaseStream.Buffer;
            int n = buf.Length;
            for (int i = n-2; i > 1; i--) buf[i+1] = buf[i];            
          }
          this.methodInfo.localVarSignature.BaseStream.Position = 0;
          this.methodInfo.localVarSignature.Write((byte)7);
          Ir2md.WriteCompressedInt(this.methodInfo.localVarSignature, this.methodInfo.localVarIndex.Count);
          Debug.Assert(this.methodInfo.localVarIndex.Count <= 0xFFFE);
        }
        this.methodBodiesHeap.Write((int)localVarSigTok);
      }else{
        //Emit tiny header
        this.methodBodiesHeap.Write((byte)(codeSize<<2 | 2));
      }
      //Copy body to bodies heap
      ((MemoryStream)this.methodBodyHeap.BaseStream).WriteTo(this.methodBodiesHeap.BaseStream);
      int pad = (int)this.methodBodiesHeap.BaseStream.Position;
      while (pad % 4 != 0){ pad++; this.methodBodiesHeap.Write((byte)0);}
      if (fatHeader) {
        //Emit exception handler entries
        int[] tryOffsets = new int[exceptionHandlersCount];
        int[] tryLengths = new int[exceptionHandlersCount];
        int[] handlerOffsets = new int[exceptionHandlersCount];
        int[] handlerLengths = new int[exceptionHandlersCount];
        bool fatFormat = false;
        for (int i = 0; i < exceptionHandlersCount; i++) {
          ExceptionHandler eh = method.ExceptionHandlers[i];
          int tryOffset = tryOffsets[i] = (int)this.methodInfo.fixupIndex[eh.TryStartBlock.UniqueKey];
          int tryLength = tryLengths[i] = ((int)this.methodInfo.fixupIndex[eh.BlockAfterTryEnd.UniqueKey]) - tryOffset;
          int handlerOffset = handlerOffsets[i] = (int)this.methodInfo.fixupIndex[eh.HandlerStartBlock.UniqueKey];
          int handlerLength = handlerLengths[i] = ((int)this.methodInfo.fixupIndex[eh.BlockAfterHandlerEnd.UniqueKey]) - handlerOffset;
          if (tryOffset > 0xffff || tryLength > 0xff || handlerOffset > 0xffff || handlerLength > 0xff) fatFormat = true;
        }
        if (exceptionHandlersCount*12 + 4 > 0xff) fatFormat = true;
        if (fatFormat) {
          int dataSize = exceptionHandlersCount*24+4;
          this.methodBodiesHeap.Write((byte)0x41);
          this.methodBodiesHeap.Write((byte)(dataSize & 0xff));
          this.methodBodiesHeap.Write((short)((dataSize >> 8) & 0xffff));
        } else {
          int dataSize = exceptionHandlersCount*12+4;
          this.methodBodiesHeap.Write((byte)0x01);
          this.methodBodiesHeap.Write((byte)dataSize);
          this.methodBodiesHeap.Write((short)0);
        }
        for (int i = 0; i < exceptionHandlersCount; i++) {
          ExceptionHandler eh = method.ExceptionHandlers[i];
          byte flags = 0;
          switch (eh.HandlerType) {
            case NodeType.Filter: flags = 0x0001; break;
            case NodeType.Finally: flags = 0x0002; break;
            case NodeType.FaultHandler: flags = 0x0004; break;
          }
          if (fatFormat) {
            this.methodBodiesHeap.Write((int)flags);
            this.methodBodiesHeap.Write((int)tryOffsets[i]);
            this.methodBodiesHeap.Write((int)tryLengths[i]);
            this.methodBodiesHeap.Write((int)handlerOffsets[i]);
            this.methodBodiesHeap.Write((int)handlerLengths[i]);
          } else {
            this.methodBodiesHeap.Write((short)flags);
            this.methodBodiesHeap.Write((ushort)tryOffsets[i]);
            this.methodBodiesHeap.Write((byte)tryLengths[i]);
            this.methodBodiesHeap.Write((ushort)handlerOffsets[i]);
            this.methodBodiesHeap.Write((byte)handlerLengths[i]);
          }
          if (eh.FilterType != null)
            this.methodBodiesHeap.Write((int)this.GetTypeToken(eh.FilterType));
          else if (eh.FilterExpression != null)
            this.methodBodiesHeap.Write((int)this.methodInfo.fixupIndex[eh.FilterExpression.UniqueKey]);
          else
            this.methodBodiesHeap.Write((int)0);
        }
      }
#if !ROTOR
      if (this.symWriter != null){
        MethodInfo mInfo = this.methodInfo;
        NodeList statementNodes = mInfo.statementNodes;
        Int32List statementOffsets = mInfo.statementOffsets;
        if (statementNodes.Count == 0)
        {
          // hack to make sure there is at least one sequence point
          statementNodes.Add(new Statement(NodeType.Nop, new SourceContext(HiddenDocument.Document)));
        }
        int n = statementNodes.Count;
        int j = 0;
        int k = 0;
        Document d = null;
        ISymUnmanagedDocumentWriter doc = null;
        for (int i = 0; i < n; i++){
          Document e = statementNodes[i].SourceContext.Document;
          if (e == null) continue;
          // don't switch doc for hidden
          if (e != HiddenDocument.Document && e != d){
            d = e;
            if (doc != null) this.DefineSequencePoints(statementNodes, statementOffsets, j, k, doc);
            doc = this.GetDocumentWriter(d);
            j = i;
            k = 0;
          }
          k++;
        }
        if (doc == null)
        {
          // find any doc as we seem to have just a hidden program point
          doc = this.GetArbitraryDocWriter();
        }
        if (doc != null)
        {
          this.DefineSequencePoints(statementNodes, statementOffsets, j, k, doc);
        }
        this.symWriter.CloseScope((uint)this.methodBodyHeap.BaseStream.Position);
#if CodeContracts
        if (method.ExtraDebugInfo != null)
        {
          method.ExtraDebugInfo.Write(methodDefToken, this.symWriter, this);
        }
#endif
        this.symWriter.CloseMethod();
      }
#endif
      //this.methodBodyHeap = null;
      //this.methodInfo = null;
      //this.currentMethod = null;
    }

#if !ROTOR
    private void DefineLocalVariables(int startAddress, LocalList locals) {
      MethodInfo mInfo = this.methodInfo;
      for(int i = 0, n = locals.Count; i < n; i++) {
        Local loc = locals[i];
        string name = loc.Name.ToString();
        unsafe {
          fixed(byte* p = mInfo.localVarSignature.BaseStream.Buffer) {
            IntPtr sp = (IntPtr)(p + mInfo.signatureOffsets[i]);
            uint c = (uint)mInfo.signatureLengths[i];
            uint attributes = loc.Attributes;
            if (!loc.HasNoPDBInfo)
            {
              this.symWriter.DefineLocalVariable(name, attributes, c, sp, 1u, (uint)this.GetLocalVarIndex(loc), 0u, 0u, 0u);
            }
          }
        }
      }
      int posOfFirstInstructionOfNextBlock = this.methodBodyHeap.BaseStream.Position;
      if (posOfFirstInstructionOfNextBlock > startAddress)
        this.symWriter.CloseScope((uint)(posOfFirstInstructionOfNextBlock - 1));
      else
        this.symWriter.CloseScope((uint)startAddress);
    }
#endif
    void DefineSequencePoint(Node node){
#if !ROTOR
      if (this.symWriter != null && node != null && node.SourceContext.Document != null && !node.SourceContext.Document.Hidden){
        if (this.methodInfo.statementNodes.Count > 0)
        {
          var previous = this.methodInfo.statementNodes[this.methodInfo.statementNodes.Count - 1];
          if (previous != null && 
              previous.SourceContext.Document == node.SourceContext.Document &&
              previous.SourceContext.StartPos == node.SourceContext.StartPos &&
              previous.SourceContext.EndPos == node.SourceContext.EndPos) return;
        }
        this.methodInfo.statementNodes.Add(node);
        this.methodInfo.statementOffsets.Add(this.methodBodyHeap.BaseStream.Position);
      }
#endif
    }
#if !ROTOR
    void DefineSequencePoints(NodeList/*!*/ statementNodes, Int32List/*!*/ statementOffsets, int start, int count, ISymUnmanagedDocumentWriter doc) 
      //^ requires this.symWriter != null;
    {
      if (count == 0) return;
      uint[] offsets = new uint[count];
      uint[] lines = new uint[count];
      uint[] columns = new uint[count];
      uint[] endLines = new uint[count];
      uint[] endColumns = new uint[count];
      for (int i = 0; i < count; i++){
        Node n = statementNodes[i+start];
        offsets[i] = i+start == 0 ? 0 : (uint)statementOffsets[i+start];
        lines[i] = (uint)n.SourceContext.StartLine;
        columns[i] = (uint)n.SourceContext.StartColumn;
        endLines[i] = (uint)n.SourceContext.EndLine;
        endColumns[i] = (uint)n.SourceContext.EndColumn;
      }
      this.symWriter.DefineSequencePoints(doc, (uint)count, offsets, lines, columns, endLines, endColumns);
    }
#endif
    void VisitModule(Module/*!*/ module) {
      //REVIEW: check that module has no explicit lists of assembly/module references?
      //this.ForceTemplateTypeMethodBodiesToGetSpecialized(module);
      this.VisitAttributeList(module.Attributes, module);
      if (this.assembly != null){
        Module m = new Module();
        m.Attributes = this.assembly.ModuleAttributes;
        this.VisitAttributeList(m.Attributes, m);
        this.VisitSecurityAttributeList(this.assembly.SecurityAttributes, this.assembly);
      }
      TypeNodeList allTypes = module.Types.Clone(); 
      for (int k = 0; k < allTypes.Count; ){
        int typeCount = module.Types.Count;
        for (int i = k, n = k, m = allTypes.Count; i < (n = allTypes.Count);){
          for (; i < n; i++){
            TypeNode t = allTypes[i];
            if (t == null) continue;
            if (this.UseGenerics && t.Template != null && t.Template.IsGeneric){
              allTypes[i] = null;
              continue;
            }
            this.GetTypeDefIndex(t);
            if (i >= m) this.nestedClassEntries.Add(t);
            MemberList members = t.Members;
            if (members != null) {
              for (int j = 0, numMembers = members.Count; j < numMembers; j++) {
                TypeNode nt = members[j] as TypeNode;
                if (nt != null) allTypes.Add(nt);
              }
            }
          }
        }
        for (int i = k, n = allTypes.Count; i < n; i++){
          TypeNode t = allTypes[i];
          if (t == null) continue;
          if (this.UseGenerics && t.Template != null && t.Template.IsGeneric){
            allTypes[i] = null;
            continue;
          }
          MemberList mems = t.Members;
          if (t is EnumNode){ //Work around JIT bug in Beta2
            for (int jj = 0, mm = mems.Count; jj < mm; jj++) {
              Field f = mems[jj] as Field;
              if (f == null || f.IsStatic) continue;
              mems[jj] = mems[0];
              mems[0] = f;
              break;
            }
          }
          for (int j = 0, m = mems.Count; j < m; j++) {
            Member mem = mems[j];
            if (mem == null) continue;
            switch(mem.NodeType){
              case NodeType.Field: this.GetFieldIndex((Field)mem); break;
              case NodeType.Method:
              case NodeType.InstanceInitializer:
              case NodeType.StaticInitializer: 
                Method meth = (Method)mem;
                if (this.UseGenerics && meth.Template != null && meth.Template.IsGeneric)
                  this.GetMethodSpecIndex(meth);
                else
                  this.GetMethodIndex(meth); 
                break;
            }
          }
        }
        for (int i = k, n = allTypes.Count; i < n; i++, k++){
          TypeNode t = allTypes[i];
          if (t == null) continue;
          this.Visit(t);
        }
        for (int i = typeCount, n = module.Types.Count; i < n; i++){
          TypeNode t = module.Types[i];
          if (t == null) continue;
          Debug.Assert(t.IsNotFullySpecialized);
          //allTypes.Add(t);
        }
      }
    }
#if !CodeContracts
    sealed class MethodSpecializer : StandardVisitor{
      private Module/*!*/ module;

      internal MethodSpecializer(Module/*!*/ module) {
        this.module = module;
        //^ base();
      }

      public override Method VisitMethod(Method method) {
        if (method == null) return null;
        if (method.Template == null || method.Template.IsGeneric) return method;
        TypeNodeList templateParameters = null;
        TypeNodeList templateArguments = null;
        if (method.TemplateArguments != null && method.TemplateArguments.Count > 0){
          templateParameters = method.Template.TemplateParameters;
          templateArguments = method.TemplateArguments;
        }else{
          TypeNode tdt = method.Template.DeclaringType;
          TypeNode dt = method.DeclaringType;
          templateParameters = tdt.ConsolidatedTemplateParameters;
          templateArguments = dt.ConsolidatedTemplateArguments;
          if (templateArguments == null) templateArguments = templateParameters;
        }
        if (templateParameters == null || templateParameters.Count == 0) return method;
        TypeNode declaringTemplate = method.DeclaringType == null ? null : method.DeclaringType.Template;
        bool savedNewTemplateInstanceIsRecursive = false;
        if (declaringTemplate != null){
          savedNewTemplateInstanceIsRecursive = declaringTemplate.NewTemplateInstanceIsRecursive;
          declaringTemplate.NewTemplateInstanceIsRecursive = method.DeclaringType.IsNotFullySpecialized;
        }
        Duplicator duplicator = new Duplicator(this.module, method.DeclaringType);
#if !MinimalReader && !CodeContracts
        TypeNode closureClone = null;
        if (method.Template.Scope != null && method.Template.Scope.CapturedForClosure){
          duplicator.TypesToBeDuplicated[method.Template.Scope.ClosureClass.UniqueKey] = method.Template.Scope.ClosureClass;
          duplicator.RecordOriginalAsTemplate = true;
          closureClone = duplicator.VisitTypeNode(method.Template.Scope.ClosureClass);
        }
#endif
        int n = method.Parameters == null ? 0 : method.Parameters.Count;
        int m = method.Template.Parameters == null ? 0 : method.Template.Parameters.Count;
        if (n != m){Debug.Assert(false); if (n > m) n = m;}
        for (int i = 0; i < n; i++){
          Parameter par = method.Parameters[i];
          Parameter tpar = method.Template.Parameters[i];
          if (par == null || tpar == null) continue;
          duplicator.DuplicateFor[tpar.UniqueKey] = par;
        }
        n = method.TemplateParameters == null ? 0 : method.TemplateParameters.Count;
        m = method.Template.TemplateParameters == null ? 0 : method.Template.TemplateParameters.Count;
        if (n != m && n > 0){Debug.Assert(false); if (n > m) n = m;}
        for (int i = 0; i < n; i++){
          TypeNode tpar = method.TemplateParameters[i];
          TypeNode ttpar = method.Template.TemplateParameters[i];
          if (tpar == null || ttpar == null) continue;
          duplicator.DuplicateFor[ttpar.UniqueKey] = tpar;
        }
        Method dup = duplicator.VisitMethod(method.Template);
        //^ assume dup != null;
        Specializer specializer = new Specializer(this.module, templateParameters, templateArguments);
        specializer.VisitMethod(dup);
#if !MinimalReader && !CodeContracts
        if (closureClone != null){
          specializer.VisitTypeNode(closureClone);
          if (method.TemplateArguments != null && method.TemplateArguments.Count > 0)
            closureClone.Name = Identifier.For(closureClone.Name.ToString()+closureClone.UniqueKey);
          MemberList dtMembers = method.DeclaringType.Members;
          for (int i = 0, nmems = dtMembers == null ? 0 : dtMembers.Count; i < nmems; i++){
            ClosureClass closureRef = dtMembers[i] as ClosureClass;
            if (closureRef != null && closureRef.Name.UniqueIdKey == closureClone.Name.UniqueIdKey){
              //This happens when the declaring type was instantiated after Normalizer has already injected a closure into the template
              dtMembers[i] = closureClone;
              closureClone = null;
              break;
            }
          }
          if (closureClone != null)
            method.DeclaringType.Members.Add(closureClone);
        }
#endif
        if (method.Template.DeclaringType.DeclaringModule != this.module){
          //Dealing with imported IR that misses important type information if it contains explicit stack operations (push, pop, dup) 
          //Call a helper visitor to remove these stack operations and in the process supply the missing type information.
          Unstacker unstacker = new Unstacker();
          unstacker.Visit(dup);
        }
        MethodBodySpecializer mbSpecializer = this.module.GetMethodBodySpecializer(templateParameters, templateArguments);
        mbSpecializer.methodBeingSpecialized = method;
        mbSpecializer.dummyMethod = dup;
        mbSpecializer.VisitMethod(dup);
        method.Body = dup.Body;
        // HACK to try to fix parameter declaring method back to the way it was before:
        method.Parameters = method.Parameters;
        method.ExceptionHandlers = dup.ExceptionHandlers;
        if (declaringTemplate != null)
          declaringTemplate.NewTemplateInstanceIsRecursive = savedNewTemplateInstanceIsRecursive;
        return method;
      }
    }
    void ForceTemplateTypeMethodBodiesToGetSpecialized(Module/*!*/ module) {
      MethodSpecializer visitor = new MethodSpecializer(module);
      if (module == null) return;
      TypeNodeList types = module.Types;
      if (types == null) return;
      for (int i = 0; i < types.Count; i++)
        this.ForceTemplateTypeMethodBodiesToGetSpecialized(types[i], visitor);
    }
    void ForceTemplateTypeMethodBodiesToGetSpecialized(TypeNode/*!*/ type, MethodSpecializer/*!*/ visitor) {
      if (type == null) return;
      if (type.IsNotFullySpecialized || type.IsGeneric) return;
      bool savedNewTemplateInstanceIsRecursive = type.NewTemplateInstanceIsRecursive;
      type.NewTemplateInstanceIsRecursive = type.IsNotFullySpecialized;
      MemberList members = type.Members;
      if (members == null) return;
      for (int j = 0; j < members.Count; j++){
        Member mem = members[j];
        if (mem == null) continue;
        TypeNode t = mem as TypeNode;
        if (t != null)
          this.ForceTemplateTypeMethodBodiesToGetSpecialized(t, visitor);
        else
          visitor.VisitMethod(mem as Method);
      }
      type.NewTemplateInstanceIsRecursive = savedNewTemplateInstanceIsRecursive;
    }
#endif

    void VisitParameter(Parameter/*!*/ parameter) {
      this.IncrementStackHeight();
#if !MinimalReader
      ParameterBinding pb = parameter as ParameterBinding;
      if (pb != null) parameter = pb.BoundParameter;
#endif
      int pi = parameter.ArgumentListIndex;
      switch(pi){
        case 0: this.methodBodyHeap.Write((byte)0x02); return;
        case 1: this.methodBodyHeap.Write((byte)0x03); return;
        case 2: this.methodBodyHeap.Write((byte)0x04); return;
        case 3: this.methodBodyHeap.Write((byte)0x05); return;
        default:
          if (pi < 256){
            this.methodBodyHeap.Write((byte)0x0e);
            this.methodBodyHeap.Write((byte)pi);
          }else{
            this.methodBodyHeap.Write((byte)0xfe);
            this.methodBodyHeap.Write((byte)0x09);
            this.methodBodyHeap.Write((ushort)pi);
          }
          return;
      }
    }
    void VisitProperty(Property/*!*/ property) {
      object pindex = this.propertyIndex[property.UniqueKey];
      if (pindex != null) return;
      int index = this.propertyEntries.Count+1;
      this.propertyEntries.Add(property);
      this.propertyIndex[property.UniqueKey] = index;
      object pmindex = this.propertyMapIndex[property.DeclaringType.UniqueKey];
      if (pmindex == null){
        this.propertyMapEntries.Add(property);
        this.propertyMapIndex[property.DeclaringType.UniqueKey] = this.propertyMapEntries.Count;
      }
      if (property.Getter != null) this.methodSemanticsEntries.Add(property);
      if (property.Setter != null) this.methodSemanticsEntries.Add(property);
      if (property.OtherMethods != null)
        for (int i = 0, n = property.OtherMethods.Count; i < n; i++) 
          this.methodSemanticsEntries.Add(property);
      this.VisitAttributeList(property.Attributes, property);
    }
    void VisitReferencedType(TypeNode type) {
      if (type == null) return;
      if (type.IsGeneric && type.Template == null){
        TypeNodeList templParams = type.ConsolidatedTemplateParameters;
        for (int i = 0, n = templParams == null ? 0 : templParams.Count; i < n; i++)
          this.typeParameterNumber[templParams[i].UniqueKey] = i+1;
      }
      switch(type.typeCode){
        case ElementType.Pointer: this.VisitReferencedType(((Pointer)type).ElementType); return;
        case ElementType.Reference: this.VisitReferencedType(((Reference)type).ElementType); return;
        case ElementType.Array:
        case ElementType.SzArray: this.VisitReferencedType(((ArrayType)type).ElementType); return;
        case ElementType.OptionalModifier:
        case ElementType.RequiredModifier:
          TypeModifier tm = (TypeModifier)type;
          this.VisitReferencedType(tm.Modifier);
          this.VisitReferencedType(tm.ModifiedType);
          return;
        case ElementType.FunctionPointer: 
          FunctionPointer fp = (FunctionPointer)type;
          this.VisitReferencedType(fp.ReturnType);
          for (int i = 0, n = fp.ParameterTypes == null ? 0 : fp.ParameterTypes.Count; i < n; i++)
            this.VisitReferencedType(fp.ParameterTypes[i]);
          return;
        case ElementType.ValueType: 
        case ElementType.Class: 
          break;
        default: 
          return;
      }
      if (this.IsStructural(type) && (!type.IsGeneric || (type.Template != null && type.ConsolidatedTemplateArguments != null && type.ConsolidatedTemplateArguments.Count > 0)))
        this.GetTypeSpecIndex(type);
      else if (type.DeclaringModule == this.module)
        this.GetTypeDefIndex(type);
      else if (type.DeclaringModule != null)
        this.GetTypeRefIndex(type);
      else if (type.typeCode == ElementType.ValueType || type.typeCode == ElementType.Class){
        //Get here for type parameters
        if (this.UseGenerics && this.typeParameterNumber[type.UniqueKey] != null) return;
        type.DeclaringModule = this.module;
        this.GetTypeDefIndex(type);
      }else
        Debug.Assert(false);
    }
    void VisitReturn(Return/*!*/ Return) {
      this.DefineSequencePoint(Return);
      if (Return.Expression != null){
        this.Visit(Return.Expression);
        this.stackHeight--;
      }
      this.methodBodyHeap.Write((byte)0x2a);
    }
    void VisitSecurityAttributeList(SecurityAttributeList attrs, Node/*!*/ node) {
      if (attrs == null) return;
      int n = attrs.Count;
      if (n == 0) return;
      int m = n;
      for (int j = 0; j < n; j++){
        SecurityAttribute a = attrs[j];
        if (a == null) m--;
      }
      if (m == 0) return;
      n = m;
      int codedIndex = this.GetSecurityAttributeParentCodedIndex(node);
      this.securityAttributeCount += n;
      m = this.nodesWithSecurityAttributes.Count;
      this.nodesWithSecurityAttributes.Add(node);
      int i = 0; //after the for loop i will be position where the new node should be in sorted list
      NodeList nodes = this.nodesWithSecurityAttributes;
      for (i = m; i > 0; i--){
        Node other = nodes[i-1];
        int oci = this.GetSecurityAttributeParentCodedIndex(other);
        if (oci < codedIndex) break;
      }
      if (i == m) return; //node is already where it should be
      for (int j = m; j > i; j--) nodes[j] = nodes[j-1]; //Make space at postion i
      nodes[i] = node;
    }
    void VisitStatement(Statement/*!*/ statement) {
      this.DefineSequencePoint(statement);
      switch(statement.NodeType){
        case NodeType.Nop: this.methodBodyHeap.Write((byte)0x00); break;
        case NodeType.DebugBreak: this.methodBodyHeap.Write((byte)0x01); break;
        case NodeType.EndFinally: this.methodBodyHeap.Write((byte)0xdc); break;
      }
    }
    void VisitStruct(Struct/*!*/ Struct) {
      if (this.UseGenerics && Struct.Template != null && Struct.Template.IsGeneric) return;
      this.VisitAttributeList(Struct.Attributes, Struct);
      this.VisitSecurityAttributeList(Struct.SecurityAttributes, Struct);
      this.VisitReferencedType(CoreSystemTypes.ValueType);
      InterfaceList interfaces = Struct.Interfaces;
      for (int i = 0, n = interfaces == null ? 0 : interfaces.Count; i < n; i++) {
        this.GetTypeDefOrRefOrSpecEncoded(interfaces[i]);
        if (interfaces[i] != null) this.interfaceEntries.Add(Struct);
      }
      for (int i = 0, n = Struct.Members.Count; i < n; i++) {
        Member m = Struct.Members[i];
        if (m is TypeNode) continue;
        this.Visit(m);
      }
      if ((Struct.Flags & (TypeFlags.ExplicitLayout|TypeFlags.SequentialLayout)) != 0 && (Struct.PackingSize != 0 || Struct.ClassSize != 0))
        this.classLayoutEntries.Add(Struct);
    }
    void VisitSwitchInstruction(SwitchInstruction/*!*/ switchInstruction) {
      this.Visit(switchInstruction.Expression);
      this.stackHeight--;
      BlockList targets = switchInstruction.Targets;
      int n = targets != null ? targets.Count : 0;
      int addressOfNextInstruction = ((int)this.methodBodyHeap.BaseStream.Position) + 5 + 4*n;
      this.methodBodyHeap.Write((byte)0x45);
      this.methodBodyHeap.Write((uint)n);
      for (int i = 0; i < n; i++)
        this.methodBodyHeap.Write((int)this.GetOffset(targets[i], addressOfNextInstruction));
    }
    void VisitTernaryExpression(TernaryExpression/*!*/ expression) {
      this.Visit(expression.Operand1);
      this.Visit(expression.Operand2);
      this.Visit(expression.Operand3);
      this.methodBodyHeap.Write((byte)0xfe);
      if (expression.NodeType == NodeType.Cpblk)
        this.methodBodyHeap.Write((byte)0x17);
      else
        this.methodBodyHeap.Write((byte)0x18);
      this.stackHeight-=3;
    }
    void VisitThis(This/*!*/ This) {
      this.IncrementStackHeight();
      this.methodBodyHeap.Write((byte)0x02);
    }
    void VisitThrow(Throw/*!*/ Throw) {
      this.DefineSequencePoint(Throw);
      if (Throw.NodeType == NodeType.Rethrow){
        this.methodBodyHeap.Write((byte)0xfe);
        this.methodBodyHeap.Write((byte)0x1a);
      }else{
        this.Visit(Throw.Expression);
        this.methodBodyHeap.Write((byte)0x7a);
      }
      this.stackHeight--;
    }
    void VisitUnaryExpression(UnaryExpression/*!*/ unaryExpression) {
      switch(unaryExpression.NodeType){      
        case NodeType.Ldtoken :
          this.methodBodyHeap.Write((byte)0xd0);
          Literal lit = unaryExpression.Operand as Literal;
          if (lit != null) {
            if (lit.Value == null) return;
            this.methodBodyHeap.Write((int)this.GetTypeDefToken((TypeNode)lit.Value));
          } else {
            if (unaryExpression.Operand == null) return;
            Member m = ((MemberBinding)unaryExpression.Operand).BoundMember;
            if (m == null) return;
            Method meth = m as Method;
            if (meth != null)
              this.methodBodyHeap.Write((int)this.GetMethodToken(meth));
            else
              this.methodBodyHeap.Write((int)this.GetFieldToken((Field)m));
          }
          this.IncrementStackHeight();
          return;

        case NodeType.Ldftn :
          this.methodBodyHeap.Write((byte)0xfe);
          this.methodBodyHeap.Write((byte)0x06);
          this.methodBodyHeap.Write((int)this.GetMethodToken((Method)((MemberBinding)unaryExpression.Operand).BoundMember));
          this.IncrementStackHeight();
          return;

        case NodeType.Sizeof :
          this.methodBodyHeap.Write((byte)0xfe);
          this.methodBodyHeap.Write((byte)0x1c);
          this.methodBodyHeap.Write((int)this.GetTypeToken((TypeNode)((Literal)unaryExpression.Operand).Value));
          this.IncrementStackHeight();
          return;

        case NodeType.SkipCheck:
          this.methodBodyHeap.Write((byte)0xfe);
          this.methodBodyHeap.Write((byte)0x19);
          switch (unaryExpression.Operand.NodeType){
            case NodeType.Castclass:
            case NodeType.Unbox:
              this.methodBodyHeap.Write((byte)0x01);
              break;
            default:
              Debug.Assert(false);
              this.methodBodyHeap.Write((byte)0x00);
              break;
          }
          this.VisitExpression(unaryExpression.Operand);
          return;
      }  
      this.Visit(unaryExpression.Operand);
      byte opCode = 0;
      switch(unaryExpression.NodeType){      
        case NodeType.Neg :            opCode = 0x65; break;
        case NodeType.Not :            opCode = 0x66; break;
        case NodeType.Conv_I1 :        opCode = 0x67; break;
        case NodeType.Conv_I2 :        opCode = 0x68; break;
        case NodeType.Conv_I4 :        opCode = 0x69; break;
        case NodeType.Conv_I8 :        opCode = 0x6a; break;
        case NodeType.Conv_R4 :        opCode = 0x6b; break;
        case NodeType.Conv_R8 :        opCode = 0x6c; break;
        case NodeType.Conv_U4 :        opCode = 0x6d; break;
        case NodeType.Conv_U8 :        opCode = 0x6e; break;
        case NodeType.Conv_R_Un :      opCode = 0x76; break;
        case NodeType.Conv_Ovf_I1_Un : opCode = 0x82; break;
        case NodeType.Conv_Ovf_I2_Un : opCode = 0x83; break;
        case NodeType.Conv_Ovf_I4_Un : opCode = 0x84; break;
        case NodeType.Conv_Ovf_I8_Un : opCode = 0x85; break;
        case NodeType.Conv_Ovf_U1_Un : opCode = 0x86; break;
        case NodeType.Conv_Ovf_U2_Un : opCode = 0x87; break;
        case NodeType.Conv_Ovf_U4_Un : opCode = 0x88; break;
        case NodeType.Conv_Ovf_U8_Un : opCode = 0x89; break;
        case NodeType.Conv_Ovf_I_Un :  opCode = 0x8a; break;
        case NodeType.Conv_Ovf_U_Un :  opCode = 0x8b; break;
        case NodeType.Ldlen :          opCode = 0x8e; break;
        case NodeType.Conv_Ovf_I1 :    opCode = 0xb3; break;
        case NodeType.Conv_Ovf_U1 :    opCode = 0xb4; break;
        case NodeType.Conv_Ovf_I2 :    opCode = 0xb5; break;
        case NodeType.Conv_Ovf_U2 :    opCode = 0xb6; break;
        case NodeType.Conv_Ovf_I4 :    opCode = 0xb7; break;
        case NodeType.Conv_Ovf_U4 :    opCode = 0xb8; break;
        case NodeType.Conv_Ovf_I8 :    opCode = 0xb9; break;
        case NodeType.Conv_Ovf_U8 :    opCode = 0xba; break;
        case NodeType.Ckfinite :       opCode = 0xc3; break;
        case NodeType.Conv_U2 :        opCode = 0xd1; break;
        case NodeType.Conv_U1 :        opCode = 0xd2; break;
        case NodeType.Conv_I :         opCode = 0xd3; break;
        case NodeType.Conv_Ovf_I :     opCode = 0xd4; break;
        case NodeType.Conv_Ovf_U :     opCode = 0xd5; break;
        case NodeType.Conv_U :         opCode = 0xe0; break;
        case NodeType.Localloc :       opCode = 0x0f; this.methodBodyHeap.Write((byte)0xfe); break;
        case NodeType.Refanytype :     opCode = 0x1d; this.methodBodyHeap.Write((byte)0xfe); break;
      }
      this.methodBodyHeap.Write((byte)opCode);
    }
    static void WriteArrayShape(BinaryWriter/*!*/ target, ArrayType/*!*/ arrayType) {
      Ir2md.WriteCompressedInt(target, arrayType.Rank);
      int n = arrayType.Sizes == null ? 0 : arrayType.Sizes.Length;
      Ir2md.WriteCompressedInt(target, n);
      for (int i = 0; i < n; i++) {
        //^ assert arrayType.Sizes != null;
        Ir2md.WriteCompressedInt(target, arrayType.Sizes[i]);
      }
      n = arrayType.LowerBounds == null ? 0 : arrayType.LowerBounds.Length;
      Ir2md.WriteCompressedInt(target, n);
      for (int i = 0; i < n; i++) {
        //^ assert arrayType.LowerBounds != null;
        Ir2md.WriteCompressedInt(target, arrayType.LowerBounds[i]);
      }
    }
    internal static void WriteCompressedInt(BinaryWriter/*!*/ target, int val) {
      if (val <= 0x7f)
        target.Write((byte)val);
      else if (val < 0x3fff){
        target.Write((byte)((val >> 8)|0x80));
        target.Write((byte)(val & 0xff));
      }else if (val < 0x1fffffff){
        target.Write((byte)((val >> 24)|0xc0));
        target.Write((byte)((val & 0xff0000)>>16));
        target.Write((byte)((val & 0xff00)>>8));
        target.Write((byte)(val & 0xff));
      }else
        Debug.Assert(false, "index too large for compression");
    }
    TypeNode/*!*/ WriteCustomModifiers(BinaryWriter/*!*/ target, TypeNode/*!*/ type) {
      switch(type.NodeType){
        case NodeType.RequiredModifier:
        case NodeType.OptionalModifier:
          TypeModifier tm = (TypeModifier)type;
          target.Write((byte)tm.typeCode);
          this.WriteTypeDefOrRefEncoded(target, tm.Modifier);
          return this.WriteCustomModifiers(target, tm.ModifiedType);
      }
      return type;
    }
    void WriteCustomAttributeLiteral(BinaryWriter/*!*/ writer, Literal/*!*/ literal, bool needsTag) {
      if (literal.Type == null) return;
      ElementType typeCode = literal.Type.typeCode;
      if (needsTag){
        if (typeCode == ElementType.ValueType){ //Boxed enum
          writer.Write((byte)0x55);
          this.WriteSerializedTypeName(writer, literal.Type);
        }else if (typeCode == ElementType.Class){ //a Type value
          writer.Write((byte)0x50);
        } else if (typeCode != ElementType.Object) //a primitive
          writer.Write((byte)typeCode);
      }
      Object value = literal.Value;
      //if (value == null) return; //TODO: nope, find some other way
      switch(typeCode){
        case ElementType.Boolean: writer.Write((bool)value); return;
        case ElementType.Char: writer.Write((ushort)(char)value); return;
        case ElementType.Double: writer.Write((double)value); return;
        case ElementType.Single: writer.Write((float)value); return; 
        case ElementType.Int16: writer.Write((short)value); return;
        case ElementType.Int32: writer.Write((int)value); return;
        case ElementType.Int64: writer.Write((long)value); return;
        case ElementType.Int8: writer.Write((sbyte)value); return;
        case ElementType.UInt16: writer.Write((ushort)value); return;
        case ElementType.UInt32: writer.Write((uint)value); return;
        case ElementType.UInt64: writer.Write((ulong)value); return;
        case ElementType.UInt8: writer.Write((byte)value); return;
        case ElementType.String: writer.Write((string)value, false); return;
        case ElementType.ValueType: this.WriteCustomAttributeLiteral(writer, new Literal(value, ((EnumNode)literal.Type).UnderlyingType), false); return;
        case ElementType.Class:
          if (value == null && literal.Type == CoreSystemTypes.Type)
            writer.Write((byte)0xff);
          else
            this.WriteSerializedTypeName(writer, (TypeNode)value); return;
        case ElementType.SzArray:
          TypeNode elemType = ((ArrayType)literal.Type).ElementType;
          if (needsTag)
            writer.Write((byte)elemType.typeCode);
          Array array = (Array)value;
          int numElems = array == null ? -1 : array.Length;
          writer.Write((int)numElems);
          bool elemNeedsTag = elemType == CoreSystemTypes.Object;
          for (int i = 0; i < numElems; i++) {
            object elemValue = array.GetValue(i);
            Literal elemLit = elemValue as Literal;
            if (elemLit == null) elemLit = new Literal(elemValue, elemType);
            this.WriteCustomAttributeLiteral(writer, elemLit, elemNeedsTag);
          }
          return;
        case ElementType.Object:
          Literal lit = (Literal)literal.Clone();
          TypeNode t = null;
          switch(Convert.GetTypeCode(lit.Value)){
            case TypeCode.Boolean: t = CoreSystemTypes.Boolean; break;
            case TypeCode.Byte: t = CoreSystemTypes.UInt8; break;
            case TypeCode.Char: t = CoreSystemTypes.Char; break;
            case TypeCode.Double: t = CoreSystemTypes.Double; break;
            case TypeCode.Int16: t = CoreSystemTypes.Int16; break;
            case TypeCode.Int32: t = CoreSystemTypes.Int32; break;
            case TypeCode.Int64: t = CoreSystemTypes.Int64; break;
            case TypeCode.SByte: t = CoreSystemTypes.Int8; break;
            case TypeCode.Single: t = CoreSystemTypes.Single; break;
            case TypeCode.String: t = CoreSystemTypes.String; break;
            case TypeCode.UInt16: t = CoreSystemTypes.UInt16; break;
            case TypeCode.UInt32: t = CoreSystemTypes.UInt32; break;
            case TypeCode.UInt64: t = CoreSystemTypes.UInt64; break;
            case TypeCode.Empty:
            case TypeCode.Object: 
              Array arr = lit.Value as Array;
              if (arr != null){
#if !NoReflection
                t = TypeNode.GetTypeNode(arr.GetType());
#else
                System.Type reflType = arr.GetType();
                System.Type reflElemType = reflType.GetElementType();
                AssemblyNode assem = AssemblyNode.GetAssembly(reflType.Assembly.Location);
                TypeNode cciElemType = assem.GetType(Identifier.For(reflElemType.Namespace), Identifier.For(reflElemType.Name));
                t = cciElemType.GetArrayType(reflType.GetArrayRank());
#endif
              }else
                t = CoreSystemTypes.Type; 
              break;
          }
          if (t == null) break;
          lit.Type = t;
          this.WriteCustomAttributeLiteral(writer, lit, true);
          return;
      }
      Debug.Assert(false, "Unexpected type in custom attribute");
    }
    static bool AttributesContains(AttributeList al, TypeNode/*!*/ a) {
      if (al == null) return false;
      for (int i = 0, n = al.Count; i < n; i++){
        if (al[i] != null && al[i].Type == a)
          return true;
      }
      return false;
    }
    void WriteMethodSignature(BinaryWriter/*!*/ target, Method/*!*/ method) {
      if (this.UseGenerics){
        if (method.Template != null && method.Template.IsGeneric){
          //Signature is being used in MethodDef table
          TypeNodeList types = method.TemplateArguments;
          int m = types == null ? 0 : types.Count;
          target.Write((byte)(method.CallingConvention|CallingConventionFlags.Generic));
          Ir2md.WriteCompressedInt(target, m);
        }else if (method.DeclaringType.Template != null && method.DeclaringType.Template.IsGeneric){
          Method unspecializedMethod = this.GetUnspecializedMethod(method);
          this.WriteMethodSignature(target, unspecializedMethod);
          return;
        }else if (method.IsGeneric){
          TypeNodeList types = method.TemplateParameters;
          int m = types == null ? 0 : types.Count;
          target.Write((byte)(method.CallingConvention|CallingConventionFlags.Generic));
          Ir2md.WriteCompressedInt(target, m);
        }else
          target.Write((byte)method.CallingConvention);
      }else
        target.Write((byte)method.CallingConvention);
      ParameterList pars = method.Parameters;
      int n = pars == null ? 0 : pars.Count;
      Ir2md.WriteCompressedInt(target, n);

      TypeNode returnType = method.ReturnType;
#if ExtendedRuntime
      if (method.HasOutOfBandContract || AttributesContains(method.ReturnAttributes, SystemTypes.NotNullAttribute)) {
        returnType = TypeNode.DeepStripModifiers(returnType, (method.Template != null) ? method.Template.ReturnType : null, SystemTypes.NonNullType, SystemTypes.NullableType);
    //    returnType = TypeNode.DeepStripModifier(returnType, SystemTypes.NullableType, (method.Template != null) ? returnType.GetTemplateInstance(returnType, returnType.TemplateArguments) : null);
      }
#endif      
      if (returnType == null) returnType = SystemTypes.Object;
      this.WriteTypeSignature(target, returnType, true);
      for (int i = 0; i < n; i++){
        Parameter p = pars[i];
        if (p == null) continue;
        TypeNode parameterType = p.Type;
#if ExtendedRuntime
        if (method.HasOutOfBandContract || AttributesContains(p.Attributes, SystemTypes.NotNullAttribute)) {
          parameterType = TypeNode.DeepStripModifiers(parameterType, (method.Template != null) ? method.Template.Parameters[i].Type : null, SystemTypes.NonNullType, SystemTypes.NullableType);
          //parameterType = TypeNode.DeepStripModifier(parameterType, SystemTypes.NullableType, (method.Template != null) ? parameterType.GetTemplateInstance(parameterType, parameterType.TemplateArguments) : null);
        }
#endif
        if (parameterType == null) parameterType = SystemTypes.Object;
        this.WriteTypeSignature(target, parameterType);
      }
    }
    void WriteMethodSpecSignature(BinaryWriter/*!*/ target, Method/*!*/ method) 
      //^ requires this.UseGenerics && method.Template != null && method.Template.IsGeneric;
    {
      Debug.Assert(this.UseGenerics && method.Template != null && method.Template.IsGeneric);
      target.Write((byte)0x0a);
      TypeNodeList types = method.TemplateArguments;
      int m = types == null ? 0 : types.Count;
      Ir2md.WriteCompressedInt(target, m);
      for (int i = 0; i < m; i++) {
        //^ assert types != null;
        this.WriteTypeSignature(target, types[i]);
      }
    }
    void WriteMethodSignature(BinaryWriter/*!*/ target, FunctionPointer/*!*/ fp) {
      target.Write((byte)fp.CallingConvention);
      TypeNodeList parTypes = fp.ParameterTypes;
      int n = parTypes == null ? 0 : parTypes.Count;
      Ir2md.WriteCompressedInt(target, n);
      if (fp.ReturnType != null)
        this.WriteTypeSignature(target, fp.ReturnType);
      int m = fp.VarArgStart;
      for (int i = 0; i < n; i++){
        //^ assert parTypes != null;
        if (i == m) target.Write((byte)0x41); //Sentinel
        this.WriteTypeSignature(target, parTypes[i]);
      }
    }
    void WritePropertySignature(BinaryWriter/*!*/ target, Property/*!*/ prop) {
      byte propHeader = (byte)0x8;
      if (!prop.IsStatic) propHeader |= (byte)0x20; //bizarre redundant way to indicate that property accessors are instance methods
      target.Write(propHeader);
      ParameterList pars = prop.Parameters;
      int n = pars == null ? 0 : pars.Count;
      Ir2md.WriteCompressedInt(target, n);
      if (prop.Type != null) this.WriteTypeSignature(target, prop.Type);
      for (int i = 0; i < n; i++) {
        //^ assert pars != null;
        Parameter par = pars[i];
        if (par == null || par.Type == null) continue;
        this.WriteTypeSignature(target, par.Type);
      }
    }
    void WriteSerializedTypeName(BinaryWriter target, TypeNode type){
      if (target == null || type == null) return;
      target.Write(this.GetSerializedTypeName(type), false);
    }
    string GetSerializedTypeName(TypeNode/*!*/ type) {
      bool isAssemblyQualified = true;
      return this.GetSerializedTypeName(type, ref isAssemblyQualified);
    }
    string GetSerializedTypeName(TypeNode/*!*/ type, ref bool isAssemblyQualified) {
      if (type == null) return null;
      this.VisitReferencedType(type);
      StringBuilder sb = new StringBuilder();
      TypeModifier tMod = type as TypeModifier;
      if (tMod != null) {
        sb.Append(this.GetTypeDefOrRefOrSpecEncoded(type));
        sb.Append('!');
        return sb.ToString();
      }
      ArrayType arrType = type as ArrayType;
      if (arrType != null) {
        type = arrType.ElementType;
        bool isAssemQual = false;
        this.AppendSerializedTypeName(sb, arrType.ElementType, ref isAssemQual);
        if (arrType.IsSzArray())
          sb.Append("[]");
        else {
          sb.Append('[');
          if (arrType.Rank == 1) sb.Append('*');
          for (int i = 1; i < arrType.Rank; i++) sb.Append(',');
          sb.Append(']');
        }
        goto done;
      }
      Pointer pointer = type as Pointer;
      if (pointer != null) {
        type = pointer.ElementType;
        bool isAssemQual = false;
        this.AppendSerializedTypeName(sb, pointer.ElementType, ref isAssemQual);
        sb.Append('*');
        goto done;
      }
      Reference reference = type as Reference;
      if (reference != null) {
        type = reference.ElementType;
        bool isAssemQual = false;
        this.AppendSerializedTypeName(sb, reference.ElementType, ref isAssemQual);
        sb.Append('&');
        goto done;
      }

      if (type.Template == null)
      {
        AppendEscapedTypeName(sb, type);
      }
      else
      {
        AppendEscapedTypeName(sb, type.Template);

        sb.Append('[');
        if (type.ConsolidatedTemplateArguments != null)
        {
          for (int i = 0; i < type.ConsolidatedTemplateArguments.Count; i++)
          {
            if (i > 0)
              sb.Append(',');

            //^ assert type.ConsolidatedTemplateArguments != null;
            bool isAssemQual = true;
            this.AppendSerializedTypeName(sb, type.ConsolidatedTemplateArguments[i], ref isAssemQual);
          }
        }
        sb.Append(']');
      }
    done:
      if (isAssemblyQualified)
        this.AppendAssemblyQualifierIfNecessary(sb, type, out isAssemblyQualified);
      return sb.ToString();
    }

    /// <summary>
    /// Appends the escaped full name of the type to a string builder.
    /// </summary>
    /// <param name="sb">String builder to append to.</param>
    /// <param name="type">Type whose full name to append.</param>
    void AppendEscapedTypeName(StringBuilder sb, TypeNode type)
    {
        // NOTE: we have to carefully deal with types defined within other types to avoid 
        // escaping the '+' character when it is used to separate inner types from their
        // declaring type.
        if (type.DeclaringType != null)
        {
            // if this type is defined within another type, append the declaring type name first
            // followed by the '+' separator
            AppendEscapedTypeName(sb, type.DeclaringType);
            sb.Append('+');
        }
        else if (type.Namespace != null)
        {
            // append the namespace name followed by a dot
            sb.Append(type.Namespace.Name);
            sb.Append('.');
        }

        // deal with the actual type name
        foreach (char c in type.Name.Name)
        {
            if (IsTypeNameReservedChar(c))
                sb.Append('\\');
            sb.Append(c);
        }
    }

    /// <summary>
    /// Determines if the provided character has a special meaning in a fully qualified type name
    /// and therefore has to be escaped if used as part of a type name identifier.
    /// </summary>
    /// <param name="ch">Character to test.</param>
    /// <returns>True if the character has to be escaped or false - otherwise.</returns>
    static bool IsTypeNameReservedChar(char ch)
    {
        return ch == ',' || ch == '[' || ch == ']' || ch == '&' || 
               ch == '*' || ch == '+' || ch == '\\';
    }

    void AppendAssemblyQualifierIfNecessary(StringBuilder/*!*/ sb, TypeNode type, out bool isAssemQualified) {
      isAssemQualified = false;
      if (type == null) return;
      AssemblyNode referencedAssembly = type.DeclaringModule as AssemblyNode;
      if (referencedAssembly != null && referencedAssembly != this.module /*&& referencedAssembly != CoreSystemTypes.SystemAssembly*/) {
        sb.Append(", ");
        sb.Append(referencedAssembly.StrongName);
        isAssemQualified = true;
      }
    }
    void AppendSerializedTypeName(StringBuilder/*!*/ sb, TypeNode type, ref bool isAssemQualified) {
      if (type == null) return;
      string argTypeName = this.GetSerializedTypeName(type, ref isAssemQualified);
      if (isAssemQualified) sb.Append('[');
      sb.Append(argTypeName);
      if (isAssemQualified) sb.Append(']');
    }
    void WriteTypeDefOrRefEncoded(BinaryWriter/*!*/ target, TypeNode/*!*/ type) {
      if (!type.IsGeneric && this.IsStructural(type) && !(type is ITypeParameter))
        this.WriteTypeSpecEncoded(target, type);
      else if (type.DeclaringModule == this.module)
        this.WriteTypeDefEncoded(target, type);
      else if (type.DeclaringModule != null)
        this.WriteTypeRefEncoded(target, type);
      else
        Debug.Assert(false);
    }
    void WriteTypeDefEncoded(BinaryWriter/*!*/ target, TypeNode/*!*/ type) {
      int tok = this.GetTypeDefIndex(type);
      Ir2md.WriteCompressedInt(target, (tok << 2));
    }
    void WriteTypeRefEncoded(BinaryWriter/*!*/ target, TypeNode/*!*/ type) {
      int tok = this.GetTypeRefIndex(type);
      Ir2md.WriteCompressedInt(target, (tok << 2)|1);
    }
    void WriteTypeSpecEncoded(BinaryWriter/*!*/ target, TypeNode/*!*/ type) {
      int tok = this.GetTypeSpecIndex(type);
      Ir2md.WriteCompressedInt(target, (tok << 2)|2);
    }
    void WriteTypeSignature(BinaryWriter/*!*/ target, TypeNode/*!*/ type) {
      this.WriteTypeSignature(target, type, false);
    }
    void WriteTypeSignature(BinaryWriter/*!*/ target, TypeNode/*!*/ type, bool instantiateGenericTypes) {
      if (type == null) return;
      TypeNode t = this.WriteCustomModifiers(target, type);
      if (this.UseGenerics){
        if (t.Template != null && t.Template.IsGeneric && t.TemplateParameters == null){
          target.Write((byte)0x15);
          TypeNode template = t.Template;
          while (template.Template != null) template = template.Template;
          this.WriteTypeSignature(target, template);
          TypeNodeList templArgs = t.ConsolidatedTemplateArguments;
          int n = templArgs == null ? 0 : templArgs.Count;
          Ir2md.WriteCompressedInt(target, n);
          for (int i = 0; i < n; i++) {
            //^ assume templArgs != null;
            TypeNode targ = templArgs[i];
            if (targ == null) continue;
            this.WriteTypeSignature(target, targ);
          }
          return;
        }else if (t.IsGeneric && instantiateGenericTypes){
          while (t.Template != null) t = t.Template;
          target.Write((byte)0x15);
          this.WriteTypeSignature(target, t);
          TypeNodeList templPars = t.ConsolidatedTemplateParameters;
          int n = templPars == null ? 0 : templPars.Count;
          Ir2md.WriteCompressedInt(target, n);
          for (int i = 0; i < n; i++) {
            //^ assume templPars != null;
            TypeNode tp = templPars[i];
            if (tp == null) continue;
            this.WriteTypeSignature(target, tp);
          }
          return;
        }
        if (t is ITypeParameter){
          object num  = this.typeParameterNumber[t.UniqueKey];
          if (num == null) {
            if (t is MethodTypeParameter || t is MethodClassParameter)
              num = -(((ITypeParameter)t).ParameterListIndex + 1);
            else
              num = (((ITypeParameter)t).ParameterListIndex + 1);
          }
          if (num is int){
            int number = (int)num;
            if (number < 0){
              target.Write((byte)0x1e); number = -number;
            }else
              target.Write((byte)0x13);
            Ir2md.WriteCompressedInt(target, number-1);
            return;
          }
        }
      }
      target.Write((byte)t.typeCode);
      switch(t.typeCode){
        case ElementType.Pointer: this.WriteTypeSignature(target, ((Pointer)t).ElementType); break;
        case ElementType.Reference: this.WriteTypeSignature(target, ((Reference)t).ElementType); break;
        case ElementType.ValueType: 
        case ElementType.Class: this.WriteTypeDefOrRefEncoded(target, t); break;
        case ElementType.Array: this.WriteTypeSignature(target, ((ArrayType)t).ElementType); Ir2md.WriteArrayShape(target, (ArrayType)t); break;
        case ElementType.FunctionPointer: this.WriteMethodSignature(target, (FunctionPointer)t); break;
        case ElementType.SzArray: this.WriteTypeSignature(target, ((ArrayType)t).ElementType); break;
      }
    }

#if !ROTOR  
    void IMetaDataEmit.SetModuleProps(string szName){
      throw new NotImplementedException();
    } 
    void IMetaDataEmit.Save(string szFile, uint dwSaveFlags){
      throw new NotImplementedException();
    }
    unsafe void IMetaDataEmit.SaveToStream(void* pIStream, uint dwSaveFlags){
      throw new NotImplementedException();
    } 
    uint IMetaDataEmit.GetSaveSize(uint fSave){
      throw new NotImplementedException();
    } 
    unsafe uint IMetaDataEmit.DefineTypeDef(char* szTypeDef, uint dwTypeDefFlags, uint tkExtends, uint* rtkImplements){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataEmit.DefineNestedType(char* szTypeDef, uint dwTypeDefFlags, uint tkExtends, uint* rtkImplements, uint tdEncloser){
      throw new NotImplementedException();
    } 
    void IMetaDataEmit.SetHandler([MarshalAs(UnmanagedType.IUnknown), In]object pUnk){
      throw new NotImplementedException();
    } 
    unsafe uint IMetaDataEmit.DefineMethod(uint td, char* zName, uint dwMethodFlags, byte* pvSigBlob, uint cbSigBlob, uint ulCodeRVA, uint dwImplFlags){
      throw new NotImplementedException();
    }   
    void IMetaDataEmit.DefineMethodImpl(uint td, uint tkBody, uint tkDecl){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataEmit.DefineTypeRefByName(uint tkResolutionScope, char* szName){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataEmit.DefineImportType(IntPtr pAssemImport, void* pbHashValue, uint cbHashValue, IMetaDataImport pImport,
      uint tdImport, IntPtr pAssemEmit){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataEmit.DefineMemberRef(uint tkImport, string szName, byte* pvSigBlob, uint cbSigBlob){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataEmit.DefineImportMember(IntPtr pAssemImport, void* pbHashValue, uint cbHashValue, 
      IMetaDataImport pImport, uint mbMember, IntPtr pAssemEmit, uint tkParent){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataEmit.DefineEvent(uint td, string szEvent, uint dwEventFlags, uint tkEventType, uint mdAddOn, uint mdRemoveOn, uint mdFire, uint *rmdOtherMethods){
      throw new NotImplementedException();
    }
    unsafe void IMetaDataEmit.SetClassLayout(uint td, uint dwPackSize, COR_FIELD_OFFSET* rFieldOffsets, uint ulClassSize){
      throw new NotImplementedException();
    }
    void IMetaDataEmit.DeleteClassLayout(uint td){
      throw new NotImplementedException();
    }
    unsafe void IMetaDataEmit.SetFieldMarshal(uint tk, byte* pvNativeType, uint cbNativeType){
      throw new NotImplementedException();
    }
    void IMetaDataEmit.DeleteFieldMarshal(uint tk){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataEmit.DefinePermissionSet (uint tk, uint dwAction, void* pvPermission, uint cbPermission){
      throw new NotImplementedException();
    }
    void IMetaDataEmit.SetRVA(uint md, uint ulRVA){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataEmit.GetTokenFromSig(byte* pvSig, uint cbSig){
      BinaryWriter sig = new BinaryWriter(new MemoryStream());
      for (int i = 0; i < cbSig; i++) sig.Write(*(pvSig+i));
      return (uint)(0x11000000 | this.GetStandAloneSignatureIndex(sig));
    }
    uint IMetaDataEmit.DefineModuleRef(string szName){
      throw new NotImplementedException();
    }
    void IMetaDataEmit.SetParent(uint mr, uint tk){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataEmit.GetTokenFromTypeSpec(byte* pvSig, uint cbSig){
      throw new NotImplementedException();
    }
    unsafe void IMetaDataEmit.SaveToMemory(void* pbData, uint cbData){
      throw new NotImplementedException();
    }
    uint IMetaDataEmit.DefineUserString(string szString, uint cchString){
      throw new NotImplementedException();
    }
    void IMetaDataEmit.DeleteToken(uint tkObj){
      throw new NotImplementedException();
    }
    void IMetaDataEmit.SetMethodProps(uint md, uint dwMethodFlags, uint ulCodeRVA, uint dwImplFlags){
      throw new NotImplementedException();
    }
    unsafe void IMetaDataEmit.SetTypeDefProps(uint td, uint dwTypeDefFlags, uint tkExtends, uint* rtkImplements){
      throw new NotImplementedException();
    }
    unsafe void IMetaDataEmit.SetEventProps(uint ev, uint dwEventFlags, uint tkEventType, uint mdAddOn, uint mdRemoveOn, uint mdFire, uint* rmdOtherMethods){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataEmit.SetPermissionSetProps(uint tk, uint dwAction, void* pvPermission, uint cbPermission){
      throw new NotImplementedException();
    }
    void IMetaDataEmit.DefinePinvokeMap(uint tk, uint dwMappingFlags, string szImportName, uint mrImportDLL){
      throw new NotImplementedException();
    }
    void IMetaDataEmit.SetPinvokeMap(uint tk, uint dwMappingFlags, string szImportName, uint mrImportDLL){
      throw new NotImplementedException();
    }
    void IMetaDataEmit.DeletePinvokeMap(uint tk){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataEmit.DefineCustomAttribute(uint tkObj, uint tkType, void* pCustomAttribute, uint cbCustomAttribute){
      throw new NotImplementedException();
    }
    unsafe void IMetaDataEmit.SetCustomAttributeValue(uint pcv, void* pCustomAttribute, uint cbCustomAttribute){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataEmit.DefineField(uint td, string szName, uint dwFieldFlags, byte* pvSigBlob, uint cbSigBlob, uint dwCPlusTypeFlag, 
      void* pValue, uint cchValue){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataEmit.DefineProperty(uint td, string szProperty, uint dwPropFlags, byte *pvSig, uint cbSig, uint dwCPlusTypeFlag, 
      void* pValue, uint cchValue, uint mdSetter, uint mdGetter, uint *rmdOtherMethods){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataEmit.DefineParam(uint md, uint ulParamSeq, string szName, uint dwParamFlags, uint dwCPlusTypeFlag, void* pValue, uint cchValue){
      throw new NotImplementedException();
    }
    unsafe void IMetaDataEmit.SetFieldProps(uint fd, uint dwFieldFlags, uint dwCPlusTypeFlag, void* pValue, uint cchValue){
      throw new NotImplementedException();
    }
    unsafe void IMetaDataEmit.SetPropertyProps(uint  pr, uint dwPropFlags, uint dwCPlusTypeFlag, void* pValue, uint cchValue, uint mdSetter, uint mdGetter, uint* rmdOtherMethods){
      throw new NotImplementedException();
    }
    unsafe void IMetaDataEmit.SetParamProps(uint pd, string szName, uint dwParamFlags, uint dwCPlusTypeFlag, void* pValue, uint cchValue){
      throw new NotImplementedException();
    }
    uint IMetaDataEmit.DefineSecurityAttributeSet(uint tkObj, IntPtr rSecAttrs, uint cSecAttrs){
      throw new NotImplementedException();
    }
    void IMetaDataEmit.ApplyEditAndContinue([MarshalAs(UnmanagedType.IUnknown)]object pImport){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataEmit.TranslateSigWithScope(IntPtr pAssemImport, void* pbHashValue, uint cbHashValue, 
      IMetaDataImport import, byte* pbSigBlob, uint cbSigBlob, IntPtr pAssemEmit, IMetaDataEmit emit, byte* pvTranslatedSig, uint cbTranslatedSigMax){
      throw new NotImplementedException();
    }
    void IMetaDataEmit.SetMethodImplFlags(uint md, uint dwImplFlags){
      throw new NotImplementedException();
    }
    void IMetaDataEmit.SetFieldRVA(uint  fd, uint ulRVA){
      throw new NotImplementedException();
    }
    void IMetaDataEmit.Merge(IMetaDataImport pImport, IntPtr pHostMapToken, [MarshalAs(UnmanagedType.IUnknown)]object  pHandler){
      throw new NotImplementedException();
    }
    void IMetaDataEmit.MergeEnd(){
      throw new NotImplementedException();
    }
    [PreserveSig] void IMetaDataImport.CloseEnum(uint hEnum){
      throw new NotImplementedException();
    }
    uint IMetaDataImport.CountEnum(uint hEnum){
      throw new NotImplementedException();
    }
    void IMetaDataImport.ResetEnum(uint hEnum, uint ulPos){
      throw new NotImplementedException();
    }
    uint IMetaDataImport.EnumTypeDefs(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rTypeDefs, uint cMax){
      throw new NotImplementedException();
    }
    uint IMetaDataImport.EnumInterfaceImpls(ref uint phEnum, uint td, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] uint[] rImpls, uint cMax){
      throw new NotImplementedException();
    }
    uint IMetaDataImport.EnumTypeRefs(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rTypeRefs, uint cMax){
      throw new NotImplementedException();
    }
    uint IMetaDataImport.FindTypeDefByName(string szTypeDef, uint tkEnclosingClass){
      throw new NotImplementedException();
    }
    Guid IMetaDataImport.GetScopeProps(StringBuilder szName, uint cchName, out uint pchName){
      throw new NotImplementedException();
    }
    uint IMetaDataImport.GetModuleFromScope(){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataImport.GetTypeDefProps(uint td, IntPtr szTypeDef, uint cchTypeDef, out uint pchTypeDef, IntPtr pdwTypeDefFlags) {
      pchTypeDef = 0;
      if (td == 0) return 0;
      TypeNode t = null;
      if ((td & 0xFF000000) == 0x1B000000) {
        t = this.typeSpecEntries[(int)(td & 0xFFFFFF)-1];
        if (t.Template != null) t = t.Template;
      } else
        t = this.typeDefEntries[(int)(td & 0xFFFFFF)-1];
      if (t == null || t.Name == null) return 0;
      string tName = GetProperFullTypeName(t);
      if (tName == null) return 0;
      pchTypeDef = (uint)tName.Length;
      if (pchTypeDef >= cchTypeDef) pchTypeDef = cchTypeDef-1;
      char* pTypeDef = (char*)szTypeDef.ToPointer();
      for (int i = 0; i < pchTypeDef; i++) *(pTypeDef+i) = tName[i];
      *(pTypeDef+pchTypeDef) = (char)0;
      uint* pFlags = (uint*)pdwTypeDefFlags.ToPointer();
      *(pFlags) = (uint)t.Flags;
      TypeNode bt = t.BaseType;
      if (bt == null) return 0;
      return (uint)this.GetTypeToken(bt);
    }
    static string GetProperFullTypeName(TypeNode type)
    {
      if (type.DeclaringType == null) return type.FullName;
      return type.Name.Name;
    }
    uint IMetaDataImport.GetInterfaceImplProps(uint iiImpl, out uint pClass) {
      throw new NotImplementedException();
    }      
    uint IMetaDataImport.GetTypeRefProps(uint tr, out uint ptkResolutionScope, StringBuilder szName, uint cchName){
      throw new NotImplementedException();
    }        
    uint IMetaDataImport.ResolveTypeRef(uint tr, [In] ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppIScope){
      throw new NotImplementedException();
    }
    uint IMetaDataImport.EnumMembers(ref uint phEnum, uint cl, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] uint[] rMembers, uint cMax){
      throw new NotImplementedException();
    } 
    uint IMetaDataImport.EnumMembersWithName(ref uint phEnum, uint cl, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rMembers, uint cMax){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataImport.EnumMethods(ref uint phEnum, uint cl, uint* rMethods, uint cMax){
      throw new NotImplementedException();
    }  
    uint IMetaDataImport.EnumMethodsWithName(ref uint phEnum, uint cl, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rMethods, uint cMax){
      throw new NotImplementedException();
    }    
    unsafe uint IMetaDataImport.EnumFields(ref uint phEnum, uint cl, uint* rFields, uint cMax){
      throw new NotImplementedException();
    }   
    uint IMetaDataImport.EnumFieldsWithName(ref uint phEnum, uint cl, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rFields, uint cMax){
      throw new NotImplementedException();
    }   
    uint IMetaDataImport.EnumParams(ref uint phEnum, uint mb, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] uint[] rParams, uint cMax){
      throw new NotImplementedException();
    }
    uint IMetaDataImport.EnumMemberRefs(ref uint phEnum, uint tkParent, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] uint[] rMemberRefs, uint cMax){
      throw new NotImplementedException();
    } 
    uint IMetaDataImport.EnumMethodImpls(ref uint phEnum, uint td, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rMethodBody, 
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rMethodDecl, uint cMax){
      throw new NotImplementedException();
    }
    uint IMetaDataImport.EnumPermissionSets(ref uint phEnum, uint tk, uint dwActions, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] uint[] rPermission, 
      uint cMax){
      throw new NotImplementedException();
    } 
    uint IMetaDataImport.FindMember(uint td, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] byte[] pvSigBlob, uint cbSigBlob){
      throw new NotImplementedException();
    }   
    uint IMetaDataImport.FindMethod(uint td, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] byte[] pvSigBlob, uint cbSigBlob){
      throw new NotImplementedException();
    }  
    uint IMetaDataImport.FindField(uint td, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] byte[] pvSigBlob, uint cbSigBlob){
      throw new NotImplementedException();
    }    
    uint IMetaDataImport.FindMemberRef(uint td, string szName, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] byte[] pvSigBlob, uint cbSigBlob){
      throw new NotImplementedException();
    }   
    unsafe uint IMetaDataImport.GetMethodProps(uint mb, out uint pClass, IntPtr szMethod, uint cchMethod, out uint pchMethod, IntPtr pdwAttr, 
      IntPtr ppvSigBlob, IntPtr pcbSigBlob, IntPtr pulCodeRVA){
      Method m = null;
      if ((mb & 0xFF000000) == 0x0A000000)
        m = this.memberRefEntries[(int)(mb & 0xFFFFFF)-1] as Method;
      else
        m = this.methodEntries[(int)(mb & 0xFFFFFF)-1];
      pchMethod = 0;
      pClass = 0;
      if (m == null || m.DeclaringType == null) return 0;
      pClass = (uint)this.GetTypeDefToken(m.DeclaringType);
      string methName = m.Name == null ? null : m.Name.ToString();
      if (methName == null) return 0;
      pchMethod = (uint)methName.Length;
      char* pMethName = (char*)szMethod.ToPointer();
      for (int i = 0; i < pchMethod; i++) *(pMethName+i) = methName[i];
      *(pMethName+pchMethod) = (char)0;
      return 0;
    }  
    unsafe uint IMetaDataImport.GetMemberRefProps(uint mr, ref uint ptk, StringBuilder szMember, uint cchMember, out uint pchMember, out byte* ppvSigBlob){
      throw new NotImplementedException();
    }   
    unsafe uint IMetaDataImport.EnumProperties(ref uint phEnum, uint td, uint* rProperties, uint cMax){
      throw new NotImplementedException();
    } 
    unsafe uint IMetaDataImport.EnumEvents(ref uint phEnum, uint td, uint* rEvents, uint cMax){
      throw new NotImplementedException();
    }  
    uint IMetaDataImport.GetEventProps(uint ev, out uint pClass, StringBuilder szEvent, uint cchEvent, out uint pchEvent, out uint pdwEventFlags, 
      out uint ptkEventType, out uint pmdAddOn, out uint pmdRemoveOn, out uint pmdFire, 
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 11)] uint[] rmdOtherMethod, uint cMax){
      throw new NotImplementedException();
    }  
    uint IMetaDataImport.EnumMethodSemantics(ref uint phEnum, uint mb, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] uint[] rEventProp, uint cMax){
      throw new NotImplementedException();
    }  
    uint IMetaDataImport.GetMethodSemantics(uint mb, uint tkEventProp){
      throw new NotImplementedException();
    }   
    uint IMetaDataImport.GetClassLayout(uint td, out uint pdwPackSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] COR_FIELD_OFFSET[] rFieldOffset, uint cMax, out uint pcFieldOffset){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataImport.GetFieldMarshal( uint tk, out byte* ppvNativeType){
      throw new NotImplementedException();
    } 
    uint IMetaDataImport.GetRVA(uint tk, out uint pulCodeRVA){
      throw new NotImplementedException();
    }  
    unsafe uint IMetaDataImport.GetPermissionSetProps(uint pm, out uint pdwAction, out void* ppvPermission){
      throw new NotImplementedException();
    }  
    unsafe uint IMetaDataImport.GetSigFromToken(uint mdSig, out byte *ppvSig){
      throw new NotImplementedException();
    }  
    uint IMetaDataImport.GetModuleRefProps(uint mur, StringBuilder szName, uint cchName){
      throw new NotImplementedException();
    } 
    uint IMetaDataImport.EnumModuleRefs(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rModuleRefs, uint cmax){
      throw new NotImplementedException();
    }  
    unsafe uint IMetaDataImport.GetTypeSpecFromToken(uint typespec, out byte * ppvSig){
      throw new NotImplementedException();
    } 
    uint IMetaDataImport.GetNameFromToken(uint tk){
      throw new NotImplementedException();
    } 
    uint IMetaDataImport.EnumUnresolvedMethods(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rMethods, uint cMax){
      throw new NotImplementedException();
    }   
    uint IMetaDataImport.GetUserString(uint stk, StringBuilder szString, uint cchString){
      throw new NotImplementedException();
    }
    uint IMetaDataImport.GetPinvokeMap(uint tk, out uint pdwMappingFlags, StringBuilder   szImportName, uint cchImportName, out uint pchImportName){
      throw new NotImplementedException();
    }
    uint IMetaDataImport.EnumSignatures(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rSignatures, uint cmax){
      throw new NotImplementedException();
    }
    uint IMetaDataImport.EnumTypeSpecs(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rTypeSpecs, uint cmax){
      throw new NotImplementedException();
    }   
    uint IMetaDataImport.EnumUserStrings(ref uint phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rStrings, uint cmax){
      throw new NotImplementedException();
    } 
    [PreserveSig]
    int IMetaDataImport.GetParamForMethodIndex(uint md, uint ulParamSeq, out uint pParam){
      throw new NotImplementedException();
    }
    uint IMetaDataImport.EnumCustomAttributes(ref uint phEnum, uint tk, uint tkType, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=4)] uint[] rCustomAttributes, uint cMax){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataImport.GetCustomAttributeProps(uint cv, out uint ptkObj, out uint ptkType, out void * ppBlob){
      throw new NotImplementedException();
    }
    uint IMetaDataImport.FindTypeRef(uint tkResolutionScope, string szName){
      throw new NotImplementedException();
    } 
    unsafe uint IMetaDataImport.GetMemberProps(uint mb, out uint pClass, StringBuilder szMember, uint cchMember, out uint pchMember, out uint pdwAttr, 
      out byte* ppvSigBlob, out uint pcbSigBlob, out uint pulCodeRVA, out uint pdwImplFlags, out uint pdwCPlusTypeFlag, out void* ppValue){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataImport.GetFieldProps(uint mb, out uint pClass, StringBuilder szField, uint cchField, out uint pchField, out uint pdwAttr, 
      out byte* ppvSigBlob,  out uint pcbSigBlob, out uint pdwCPlusTypeFlag, out void* ppValue){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataImport.GetPropertyProps(uint prop, out uint pClass, StringBuilder szProperty, uint cchProperty, out uint pchProperty, out uint pdwPropFlags, 
      out byte* ppvSig, out uint pbSig, out uint pdwCPlusTypeFlag, out void* ppDefaultValue, out uint pcchDefaultValue, out uint pmdSetter, 
      out uint pmdGetter, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 14)] uint[] rmdOtherMethod, uint cMax){
      throw new NotImplementedException();
    } 
    unsafe uint IMetaDataImport.GetParamProps(uint tk, out uint pmd, out uint pulSequence, StringBuilder szName, uint cchName, out uint pchName, 
      out uint pdwAttr, out uint pdwCPlusTypeFlag, out void* ppValue){
      throw new NotImplementedException();
    }
    unsafe uint IMetaDataImport.GetCustomAttributeByName(uint tkObj, string szName, out void* ppData){
      throw new NotImplementedException();
    }
    [PreserveSig][return: MarshalAs(UnmanagedType.Bool)]
    bool IMetaDataImport.IsValidToken( uint tk){
      throw new NotImplementedException();
    } 
    uint IMetaDataImport.GetNestedClassProps(uint tdNestedClass){
      TypeNode t = null;
      if ((tdNestedClass & 0xFF000000) == 0x1B000000)
        t = this.typeSpecEntries[(int)(tdNestedClass & 0xFFFFFF)-1];
      else
        t = this.typeDefEntries[(int)(tdNestedClass & 0xFFFFFF)-1];
      if (t == null || t.DeclaringType == null) return 0;
      return (uint)this.GetTypeToken(t.DeclaringType);
    }
    unsafe uint IMetaDataImport.GetNativeCallConvFromSig(void* pvSig, uint cbSig){
      throw new NotImplementedException();
    } 
    int IMetaDataImport.IsGlobal(uint pd){
      throw new NotImplementedException();
    }
#endif
  }  
#if WHIDBEYwithGenericsAndIEqualityComparer
  public class ByteArrayKeyComparer : IEqualityComparer, IComparer{
    int IComparer.Compare(object x, object y) {
      if (x == null || y == null) throw new ArgumentNullException();
      byte[] xa = (byte[])x;
      byte[] ya = (byte[])y;
      int n = xa.Length;
      int result = n - ya.Length;
      if (result != 0) return result;
      for (int i = 0; i < n; i++){
        result = xa[i] - ya[i];
        if (result != 0) return result;
      }
      return 0;
    }
    bool IEqualityComparer.Equals(object x, object y){
      if (x == null || y == null) return x == y;
      return ((IComparer)this).Compare(x, y) == 0;
    }
    int IEqualityComparer.GetHashCode(object/*!*/ x) {
      Debug.Assert(x != null);
      byte[] xa = (byte[])x;
      int hcode = 1;
      for (int i = 0, n = xa.Length; i < n; i++)
        hcode = hcode * 17 + xa[i];
      return hcode;
    }
  }
#elif WHIDBEYwithGenerics
  public class ByteArrayKeyComparer : IKeyComparer{
    int IComparer.Compare(object x, object y) {
      if (x == null || y == null) throw new ArgumentNullException();
      byte[] xa = (byte[])x;
      byte[] ya = (byte[])y;
      int n = xa.Length;
      int result = n - ya.Length;
      if (result != 0) return result;
      for (int i = 0; i < n; i++){
        result = xa[i] - ya[i];
        if (result != 0) return result;
      }
      return 0;
    }
    bool IKeyComparer.Equals(object x, object y){
      return ((IKeyComparer)this).Compare(x, y) == 0;
    }
    int IHashCodeProvider.GetHashCode(object x) {
      Debug.Assert(x != null);
      byte[] xa = (byte[])x;
      int hcode = 1;
      for (int i = 0, n = xa.Length; i < n; i++)
        hcode = hcode * 17 + xa[i];
      return hcode;
    }
  }
#else
  public class ByteArrayComparer : IComparer{
    int IComparer.Compare(object x, object y){
      if (x == null || y == null) throw new ArgumentNullException();
      byte[] xa = (byte[])x;
      byte[] ya = (byte[])y;
      int n = xa.Length;
      int result = n - ya.Length;
      if (result != 0) return result;
      for (int i = 0; i < n; i++){
        result = xa[i] - ya[i];
        if (result != 0) return result;
      }
      return 0;
    }
  }
  public class ByteArrayHasher : IHashCodeProvider{
    int IHashCodeProvider.GetHashCode(object x){
      Debug.Assert(x != null);
      byte[] xa = (byte[])x;
      int hcode = 1;
      for (int i = 0, n = xa.Length; i < n; i++)
        hcode = hcode*17 + xa[i];
      return hcode;
    }
  }
#endif
  internal class Fixup{
    internal int fixupLocation;
    internal int addressOfNextInstruction;
    internal bool shortOffset;
    internal Fixup nextFixUp;
  }
  internal class MethodInfo{
    readonly internal TrivialHashtable/*!*/ fixupIndex = new TrivialHashtable(16);
    internal int localVarSigTok;
    internal BinaryWriter/*!*/ localVarSignature;
    internal TrivialHashtable<int>/*!*/ localVarIndex;
#if !ROTOR
    internal NodeList/*!*/ statementNodes;
    internal LocalList/*!*/ debugLocals;
    internal Int32List/*!*/ signatureLengths;
    internal Int32List/*!*/ signatureOffsets;
    internal Int32List/*!*/ statementOffsets;
#endif

    public MethodInfo() {
      //^ base();
    }
  }
  public class KeyFileNotFoundException : System.ArgumentException{}
  public class AssemblyCouldNotBeSignedException : System.ApplicationException{}
  public class DebugSymbolsCouldNotBeWrittenException : System.ApplicationException { }
  internal class Writer {
    private Writer(){}
    internal static void WritePE(System.CodeDom.Compiler.CompilerParameters/*!*/ compilerParameters, Module/*!*/ module)
      //^ requires module.Location != null;
    {
      if (compilerParameters == null){Debug.Assert(false); return;}
      CompilerOptions options = compilerParameters as CompilerOptions;
      if (options == null)
        Writer.WritePE(module.Location, compilerParameters.IncludeDebugInformation, module, false, null, null);
      else{
        if (options.FileAlignment > 512) module.FileAlignment = options.FileAlignment;
        Writer.WritePE(module.Location, options.IncludeDebugInformation, module, options.DelaySign, options.AssemblyKeyFile, options.AssemblyKeyName);
      }
    }
    internal static void WritePE(string/*!*/ location, bool writeDebugSymbols, Module/*!*/ module) {
      Writer.WritePE(location, writeDebugSymbols, module, false, null, null);
    }
    private static void WritePE(string/*!*/ location, bool writeDebugSymbols, Module/*!*/ module, bool delaySign, string keyFileName, string keyName) {
      AssemblyNode assem = module as AssemblyNode;
      location = Path.GetFullPath(location);
      module.Directory = Path.GetDirectoryName(location);
      bool keyFileNameDoesNotExist = false;
      if (assem != null){
        assem.KeyContainerName = keyName;
        if (keyFileName != null && keyFileName.Length > 0){
          if (!File.Exists(keyFileName)) keyFileName = Path.Combine(module.Directory, keyFileName);
          if (File.Exists(keyFileName)){
            using (FileStream keyFile = File.OpenRead(keyFileName)){
              long size = keyFile.Length;
              if (size > int.MaxValue) throw new System.IO.FileLoadException();
              int n = (int)size;
              byte[] key = new byte[n];
              keyFile.Read(key, 0, n);
              assem.KeyBlob = key;
            }
          }else
            keyFileNameDoesNotExist = true;
        }
        assem.PublicKeyOrToken = Writer.GetPublicKey(assem);
      }
      using (FileStream exeFstream = new FileStream(location, FileMode.Create, FileAccess.Write, FileShare.None)){
        string debugSymbolsLocation = writeDebugSymbols ? Path.ChangeExtension(location, "pdb") : null;
        if (debugSymbolsLocation != null && File.Exists(debugSymbolsLocation))
          File.Delete(debugSymbolsLocation);
        MemoryStream exeMstream = new MemoryStream(300000);
        Ir2md.WritePE(module, debugSymbolsLocation, new BinaryWriter(exeMstream));
        exeMstream.WriteTo(exeFstream);
      }
      if (keyFileNameDoesNotExist) throw new KeyFileNotFoundException();
      if (delaySign || assem == null) return;
      if (assem.KeyBlob != null || (assem.KeyContainerName != null && assem.KeyContainerName.Length > 0)){
        try{           
          if (!Writer.StrongNameSignatureGeneration(location, keyName, assem.KeyBlob, assem.KeyBlob == null ? 0 : assem.KeyBlob.Length, IntPtr.Zero, IntPtr.Zero))
            throw new AssemblyCouldNotBeSignedException();
        }catch{
          if (!Writer.MscorsnStrongNameSignatureGeneration(location, keyName, assem.KeyBlob, assem.KeyBlob == null ? 0 : assem.KeyBlob.Length, IntPtr.Zero, IntPtr.Zero))
            throw new AssemblyCouldNotBeSignedException();
        }
      }
    }
    [DllImport("mscoree.dll", EntryPoint="StrongNameSignatureGeneration",  
       SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=true,
       CallingConvention=CallingConvention.StdCall)]
    private static extern bool StrongNameSignatureGeneration(
      string     wszFilePath,        // [in] valid path to the PE file for the assembly
      string     wszKeyContainer,    // [in] desired key container name
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)]
      byte[]     pbKeyBlob,          // [in] public/private key blob (optional)
      int      cbKeyBlob,
      IntPtr     ppbSignatureBlob,   // [out] signature blob
      IntPtr      pcbSignatureBlob);
    [DllImport("mscorsn.dll", EntryPoint="StrongNameSignatureGeneration",  
       SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=true,
       CallingConvention=CallingConvention.StdCall)]
    private static extern bool MscorsnStrongNameSignatureGeneration(
      string     wszFilePath,        // [in] valid path to the PE file for the assembly
      string     wszKeyContainer,    // [in] desired key container name
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)]
      byte[]     pbKeyBlob,          // [in] public/private key blob (optional)
      int      cbKeyBlob,
      IntPtr     ppbSignatureBlob,   // [out] signature blob
      IntPtr      pcbSignatureBlob);
    private unsafe static byte[] GetPublicKey(AssemblyNode/*!*/ assem) {
      Debug.Assert(assem != null);
      IntPtr publicKey = IntPtr.Zero;
      int size;
      try{

        if (assem.KeyBlob != null){
          Writer.StrongNameGetPublicKey(null, assem.KeyBlob, assem.KeyBlob.Length, out publicKey, out size);
          if (publicKey == IntPtr.Zero) return assem.KeyBlob;
        }else if (assem.KeyContainerName != null){
          Writer.StrongNameGetPublicKey(assem.KeyContainerName, null, 0, out publicKey, out size);
          if (publicKey == IntPtr.Zero) return null;
        }else
          return assem.PublicKeyOrToken;
        byte[] result = new byte[size];
        byte* ptr = (byte*)publicKey;
        for (int i = 0; i < size; i++) result[i] = *ptr++;
        return result;
      }catch{} {
        if (assem.KeyBlob != null){
          Writer.MscorsnStrongNameGetPublicKeyUsing(null, assem.KeyBlob, assem.KeyBlob.Length, out publicKey, out size);
          if (publicKey == IntPtr.Zero) return assem.KeyBlob;
        }else if (assem.KeyContainerName != null){
          Writer.MscorsnStrongNameGetPublicKeyUsing(assem.KeyContainerName, null, 0, out publicKey, out size);
          if (publicKey == IntPtr.Zero) return null;
        }else
          return assem.PublicKeyOrToken;
        byte[] result = new byte[size];
        byte* ptr = (byte*)publicKey;
        for (int i = 0; i < size; i++) result[i] = *ptr++;
        return result;
      }
    }
    [DllImport("mscoree.dll", EntryPoint="StrongNameGetPublicKey",  
       SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=true,
       CallingConvention=CallingConvention.StdCall)]
    private static extern bool StrongNameGetPublicKey(
      string   wszKeyContainer,    // [in] desired key container name
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)]
      byte[]   pbKeyBlob,          // [in] public/private key blob (optional)
      int     cbKeyBlob,
      [Out] out IntPtr ppbPublicKeyBlob,   // [out] public key blob
      [Out] out int     pcbPublicKeyBlob);
    [DllImport("mscorsn.dll", EntryPoint="StrongNameGetPublicKey",  
       SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=true,
       CallingConvention=CallingConvention.StdCall)]
    private static extern bool MscorsnStrongNameGetPublicKeyUsing(
      string   wszKeyContainer,    // [in] desired key container name
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)]
      byte[]   pbKeyBlob,          // [in] public/private key blob (optional)
      int     cbKeyBlob,
      [Out] out IntPtr ppbPublicKeyBlob,   // [out] public key blob
      [Out] out int     pcbPublicKeyBlob);

    internal static void WritePE(Stream/*!*/ executable, Stream debugSymbols, Module/*!*/ module) {
      MemoryStream mstream = new MemoryStream();
      Ir2md.WritePE(module, null, new BinaryWriter(mstream)); //TODO: need to write the PDB symbols to the stream
      mstream.WriteTo(executable);
    }
    internal static void WritePE(out byte[] executable, Module/*!*/ module) {
      MemoryStream mstream = new MemoryStream();
      Ir2md.WritePE(module, null, new BinaryWriter(mstream));
      executable = mstream.ToArray();
    }
    internal static void WritePE(out byte[] executable, out byte[] debugSymbols, Module/*!*/ module){
      MemoryStream mstream = new MemoryStream();
      Ir2md.WritePE(module, null, new BinaryWriter(mstream));
      executable = mstream.ToArray();
      debugSymbols = null;
    }
    internal unsafe static void AddWin32Icon(Module/*!*/ module, string win32IconFilePath) {
      if (module == null || win32IconFilePath == null) {Debug.Assert(false); return;}
      using (System.IO.FileStream resStream = File.OpenRead(win32IconFilePath)){
        Writer.AddWin32Icon(module, resStream);
      }
    }
    internal unsafe static void AddWin32Icon(Module/*!*/ module, Stream win32IconStream) {
      if (module == null || win32IconStream == null) {Debug.Assert(false); return;}
      long size = win32IconStream.Length;
      if (size > int.MaxValue) throw new System.IO.FileLoadException();
      int n = (int)size;
      byte[] buffer = new byte[n];
      win32IconStream.Read(buffer, 0, n);
      byte* pb = (byte*)Marshal.AllocHGlobal(n);
      for (int i = 0; i < n; i++) pb[i] = buffer[i];
      MemoryCursor cursor = new MemoryCursor(pb, n/*, module*/);
      if (module.Win32Resources == null) module.Win32Resources = new Win32ResourceList();
      int reserved = cursor.ReadUInt16();
      if (reserved != 0) throw new NullReferenceException();
      int resourceType = cursor.ReadUInt16();
      if (resourceType != 1) throw new NullReferenceException();
      int imageCount = cursor.ReadUInt16();
      BinaryWriter indexHeap = new BinaryWriter(new MemoryStream());
      indexHeap.Write((ushort)0); //Reserved
      indexHeap.Write((ushort)1); //idType
      indexHeap.Write((ushort)imageCount);
      Win32Resource resource = new Win32Resource();
      for (int i = 0; i < imageCount; i++){
        resource = new Win32Resource();
        resource.CodePage = 0;
        resource.Id = module.Win32Resources.Count+2;
        resource.LanguageId = 0;
        resource.Name = null;
        resource.TypeId = 3;
        resource.TypeName = null;
        indexHeap.Write(cursor.ReadByte()); //width
        indexHeap.Write(cursor.ReadByte()); //height
        indexHeap.Write(cursor.ReadByte()); //color count
        indexHeap.Write(cursor.ReadByte()); //reserved
        indexHeap.Write(cursor.ReadUInt16()); //planes
        indexHeap.Write(cursor.ReadUInt16()); //bit count
        int len = cursor.ReadInt32();
        int offset = cursor.ReadInt32();
        indexHeap.Write((int)len);
        indexHeap.Write((int)module.Win32Resources.Count+2);
        MemoryCursor c = new MemoryCursor(cursor);
        c.Position = offset;
        resource.Data = c.ReadBytes(len);
        module.Win32Resources.Add(resource);
      }
      resource.CodePage = 0;
      resource.Data = indexHeap.BaseStream.ToArray();
      resource.Id = 0x7f00;
      resource.LanguageId = 0;
      resource.Name = null;
      resource.TypeId = 0xe;
      resource.TypeName = null;
      module.Win32Resources.Add(resource);
    }
    internal unsafe static void AddWin32ResourceFileToModule(Module/*!*/ module, string/*!*/ win32ResourceFilePath) {
      if (module == null || win32ResourceFilePath == null) {Debug.Assert(false); return;}
      using (System.IO.FileStream resStream = File.OpenRead(win32ResourceFilePath)){
        Writer.AddWin32ResourceFileToModule(module, resStream);
      }
    }
    internal unsafe static void AddWin32ResourceFileToModule(Module/*!*/ module, Stream/*!*/ win32ResourceStream) {
      if (module == null || win32ResourceStream == null) {Debug.Assert(false); return;}
      long size = win32ResourceStream.Length;
      if (size > int.MaxValue) throw new System.IO.FileLoadException();
      int n = (int)size;
      byte[] buffer = new byte[n];
      win32ResourceStream.Read(buffer, 0, n);
      byte* pb = (byte*)Marshal.AllocHGlobal(n);
      for (int i = 0; i < n; i++) pb[i] = buffer[i];
      MemoryCursor cursor = new MemoryCursor(pb, n/*, module*/);
      if (module.Win32Resources == null) module.Win32Resources = new Win32ResourceList();
      while (cursor.Position < n){
        Win32Resource resource = new Win32Resource();
        resource.CodePage = 0; //Review: Should this be settable?
        int dataSize = cursor.ReadInt32();
        cursor.ReadUInt32(); //headerSize
        if (cursor.Int16(0) == -1){
          cursor.ReadInt16();
          resource.TypeId = cursor.ReadUInt16();
          resource.TypeName = null;
        }else{
          resource.TypeId = 0;
          resource.TypeName = cursor.ReadUTF16();
        }
        if (cursor.Int16(0) == -1){
          cursor.ReadInt16();
          resource.Id = cursor.ReadUInt16();
          resource.Name = null;
        }else{
          resource.Id = 0;
          resource.Name = cursor.ReadUTF16();
        }
        cursor.ReadUInt32(); //dataVersion
        cursor.ReadUInt16(); //memoryFlags
        resource.LanguageId = cursor.ReadUInt16();
        cursor.ReadUInt32(); //version
        cursor.ReadUInt32(); //characteristics
        resource.Data = cursor.ReadBytes(dataSize);
        if (resource.Data != null)
          module.Win32Resources.Add(resource);
      }
    }
    internal static void AddWin32VersionInfo(Module/*!*/ module, CompilerOptions/*!*/ options) {
      if (module == null || options == null){Debug.Assert(false); return;}
      Win32Resource resource = new Win32Resource();
      resource.CodePage = 0;
      resource.Id = 1;
      resource.LanguageId = 0;
      resource.Name = null;
      resource.TypeId = 0x10;
      resource.TypeName = null;
      resource.Data = Writer.FillInVsVersionStructure(module, options);
      if (module.Win32Resources == null) module.Win32Resources = new Win32ResourceList();
      module.Win32Resources.Add(resource);
    }
    private static byte[] FillInVsVersionStructure(Module/*!*/ module, CompilerOptions/*!*/ options) {
      AssemblyNode assembly = module as AssemblyNode;
      BinaryWriter data = new BinaryWriter(new MemoryStream(), Encoding.Unicode);
      data.Write((ushort)0); //Space for length
      data.Write((ushort)0x34); //VS_FIXEDFILEINFO length
      data.Write((ushort)0); //Type of data in version resource
      data.Write("VS_VERSION_INFO", true);
      data.Write((ushort)0); //Padding to 4 byte boundary
      // VS_FIXEDFILEINFO starts here
      data.Write((uint)0xFEEF04BD); //Signature
      data.Write((uint)0x00010000); //Version of VS_FIXEDFILEINFO
      Version fileVersion = Writer.ParseVersion(options.TargetInformation.Version, true);
      if (fileVersion == null && assembly != null) fileVersion = assembly.Version;
      if (fileVersion == null) fileVersion = new Version();
      data.Write((ushort)fileVersion.Minor);
      data.Write((ushort)fileVersion.Major);
      data.Write((ushort)fileVersion.Revision);
      data.Write((ushort)fileVersion.Build);
      Version productVersion = Writer.ParseVersion(options.TargetInformation.ProductVersion, true);
      if (productVersion == null) productVersion = fileVersion;
      data.Write((ushort)productVersion.Minor);
      data.Write((ushort)productVersion.Major);
      data.Write((ushort)productVersion.Revision);
      data.Write((ushort)productVersion.Build);
      data.Write((uint)0x3f); //FileFlagsMask
      data.Write((uint)0x0); //FileFlags
      data.Write((uint)0x4); //OS: Win32 (After all, this is a Win32 resource.)
      if (options.GenerateExecutable)
        data.Write((uint)1); //App
      else
        data.Write((uint)2); //Dll
      data.Write((uint)0); //File subtype
      data.Write((ulong)0); //File Date
      // VarFileInfo
      data.Write((ushort)0x44); //Length of VarFileInfo
      data.Write((ushort)0x0); //Length of value
      data.Write((ushort)0x1); //type (text)
      data.Write("VarFileInfo", true);
      data.Write((ushort)0); //padding to 4 byte boundary
      // Var
      data.Write((ushort)0x24); //Length of Var
      data.Write((ushort)0x04); //length of Value
      data.Write((ushort)0); //Type (binary)
      data.Write("Translation", true);
      data.Write((uint)0); //Padding
      data.Write((ushort)0x4b0); //Code Page for Unicode
      // StringFileInfo
      int positionOfInfoLength = data.BaseStream.Position;
      data.Write((ushort)0); //length of rest of resource
      data.Write((ushort)0); //Value length, always 0
      data.Write((ushort)1); //Type (text)
      data.Write("StringFileInfo", true);
      // StringInfo
      int stringInfoLengthPos = data.BaseStream.Position;
      data.Write((ushort)0); //Space for length
      data.Write((ushort)0); //Value length, always 0
      data.Write((ushort)1); //Type (text)
      data.Write("000004b0", true); //Code page for Unicode
      Writer.WriteVersionString(data, options.TargetInformation.Description, "Comments");
      Writer.WriteVersionString(data, options.TargetInformation.Company, "CompanyName");
      Writer.WriteVersionString(data, options.TargetInformation.Title, "FileDescription");
      Writer.WriteVersionString(data, Writer.ConvertToString(fileVersion), "FileVersion");
      string fileName = module.Name + (options.GenerateExecutable ? ".exe" : ".dll");
      Writer.WriteVersionString(data, fileName, "InternalName");
      Writer.WriteVersionString(data, options.TargetInformation.Copyright, "LegalCopyright");
      Writer.WriteVersionString(data, options.TargetInformation.Trademark, "LegalTrademarks");
      Writer.WriteVersionString(data, fileName, "OriginalFilename");
      Writer.WriteVersionString(data, options.TargetInformation.Product, "ProductName");
      Writer.WriteVersionString(data, Writer.ConvertToString(productVersion), "ProductVersion");
      if (assembly != null)
        Writer.WriteVersionString(data, assembly.Version == null ? "" : assembly.Version.ToString(), "Assembly Version");
      int len = data.BaseStream.Position;
      data.BaseStream.Position = stringInfoLengthPos;
      data.Write((ushort)(len-stringInfoLengthPos));
      data.BaseStream.Position = 0;
      data.Write((ushort)len);
      data.BaseStream.Position = positionOfInfoLength;
      data.Write((ushort)len-positionOfInfoLength);
      return data.BaseStream.ToArray();
    }
    private static void WriteVersionString(BinaryWriter/*!*/ data, string value, string/*!*/ key) {
      if (value == null) return;
      int totalLength = 6;
      totalLength += key.Length*2;
      totalLength += 4 - (totalLength % 4);
      totalLength += value.Length*2;
      totalLength += 4 - (totalLength % 4);
      data.Write((ushort)totalLength);
      data.Write((ushort)(value.Length+1));
      data.Write((ushort)1); //Type (text)
      data.Write(key, true);
      if (data.BaseStream.Position % 4 != 0) data.Write((char)0);
      data.Write(value, true);
      if (data.BaseStream.Position % 4 != 0) data.Write((char)0);
    }
    private static string/*!*/ ConvertToString(Version/*!*/ version) {
      StringBuilder sb = new StringBuilder();
      sb.Append(version.Major.ToString());
      if (version.Minor != 0 || version.Build != 0 || version.Revision != 0){
        sb.Append('.');
        sb.Append(version.Minor.ToString());
      }
      if (version.Build != 0 || version.Revision != 0){
        sb.Append('.');
        sb.Append(version.Build.ToString());
      }
      if (version.Revision != 0){
        sb.Append('.');
        sb.Append(version.Revision.ToString());
      }
      return sb.ToString();
    }
    private static Version ParseVersion(string vString, bool allowWildcards){
      if (vString == null) return null;
      ushort major = 1;
      ushort minor = 0;
      ushort build = 0;
      ushort revision = 0;
      try{
        int n = vString.Length;
        int i = vString.IndexOf('.', 0);
        if (i < 0) throw new FormatException();
        major = UInt16.Parse(vString.Substring(0, i), CultureInfo.InvariantCulture);
        int j = vString.IndexOf('.', i+1);
        if (j < i+1)
          minor = UInt16.Parse(vString.Substring(i+1, n-i-1), CultureInfo.InvariantCulture);
        else{
          minor = UInt16.Parse(vString.Substring(i+1, j-i-1), CultureInfo.InvariantCulture);
          if (vString[j+1] == '*' && allowWildcards){
            if (j+1 < n-1) return null; 
            build = Writer.DaysSince2000();
            revision = Writer.SecondsSinceMidnight();
          }else{
            int k = vString.IndexOf('.', j+1);
            if (k < j+1)
              build = UInt16.Parse(vString.Substring(j+1, n-j-1), CultureInfo.InvariantCulture);
            else{
              build = UInt16.Parse(vString.Substring(j+1, k-j-1), CultureInfo.InvariantCulture);
              if (vString[k+1] == '*' && allowWildcards){
                if (j+1 < n-1) return null; 
                revision = Writer.SecondsSinceMidnight();
              }else
                revision = UInt16.Parse(vString.Substring(k+1, n-k-1), CultureInfo.InvariantCulture);
            }
          }
        }
      }catch(FormatException){
        major = minor = build = revision = UInt16.MaxValue;
      }catch(OverflowException){
        major = minor = build = revision = UInt16.MaxValue;
      }
      if (major == UInt16.MaxValue && minor == UInt16.MaxValue && build == UInt16.MaxValue && revision == UInt16.MaxValue){
        return null;
      }
      return new Version(major, minor, build, revision);
    }
    private static ushort DaysSince2000(){
      return (ushort)(DateTime.Now - new DateTime(2000, 1, 1)).Days;
    }
    private static ushort SecondsSinceMidnight(){
      TimeSpan sinceMidnight = DateTime.Now - DateTime.Today;
      return (ushort)((sinceMidnight.Hours*60*60+sinceMidnight.Minutes*60+sinceMidnight.Seconds)/2);
    }

  }
}
#endif
